
So let's go. Uh today we're going to talk about the age of zote injection. How to break Android boxing system. First of all, who am I? I am drone. Can you call me Trito? Uh I'm 19 years old Brazilian pain tester researcher and Mario developer at Hakai offensive security. Uh, Hakai is a focus company on offensive security like services like P testing, red teaming and threat intelligence and other so on. I'm programmer gamer. I love cats. If you're going to eat some pizza, please call me. And I'm passionate about C internals, reverse engineering, development and mobile. Uh, here we have a care code for my GitHub if you want to check my job and others things other projects. So
okay what is the intention? Uh the I want to explain to you how zygote injections attacks work and what we can do with it like is a pretty great uh alternative for tools like Freda or debuggers for instrumentating mobile applications. Uh and that's it. Let's go. Uh it's pretty cool because I go injection is a more stealth way we can bypass protections more quickly like uh we don't have to care about Freda or debugger detections just check some so okay let's go uh first of all what is zygot zygote the zygote process is the first process started Android is the parent process of all the Android applications um and inside of zygote we have the
Android runtime that will care about like the policy Linux and the interpretation of the code. So Android have the zygote and when does I go need to generate an application like you open WhatsApp, Instagram another application the zygote will do a fork and this fork uh is for put the code inside the runtime and can run the code itself. uh zot runs with limited privilege. So it applies the sea policy Linux inside each application to limit it. So one application can't talk with the other. Uh we have got some process that are being started by zote like system server web and all the other app process and we have the specialization. specialization is exactly this point to uh the zot fork
itself and set the security measures for this process. So when we set the security methods based on the Linux policies uh this we call specialization. So okay here we have a diagram. So the Android start the car and the system. uh in this time we have some services like install dab ADB uh for interacting with the system install some applications and we have the zygote process and from the zote process we will uh fork and generate the others the other process that need security measures. So okay we have Android runtime android runtime is the manager runtime that the applications will use to run it code. Uh the format that Android runtime understand is the executable that is a
bite code format specific for Android. Uh and on the interpretation method the execution method we have a hybrid compilation. So we have GT and AOT DT is the uh process of pass in the interpretation. So the just in time compilation will pass through the interpreter and on AOT is ahead of time compilation. The code will be pre-ompiled when the interpreter being uh execute frequently. So we pre-ompile this code on on the Android the Android does this for us and the code will be is like for optimization is just convert for machine code. Um we have the difference between Java cotling code and native code. Java and cotling code will generate dex format and we have the native code. The
native code is like IOT but you preo compile the code on your machine and passing format as a dynamic link casual library. Uh we have the difference between two libraries inside the Android we have the lib android runtime. So and libarso they are different. Uh lib Android runtime is for apply the security measures is the simple Linux that will be applied or the fork or the specialization is the environment setup and libard. is the interpreter and what will execute our code. Uh okay, here we have just a diagram. So JT code will be the interpreter. We have a white code dex format and they will turn into machine code and execute. And the we have the frequently run code like
50% uh that will pre-ompile on our machine and just run as machine code all the process no need to interpret the code. Uh we have this pretty weird diagram too but we can focus on the red boxes. Uh this is what liar that I showed us. We have here this side. Uh that is the interpretation uh execution. Here all the code that is GT will be interpreted and here on this other side on native method is the methods that we preo compile on our machine and pass in uh the clinic library format and we have quick code. Quick code is AOT. AOT is the frequent code that was interpreted but now the Android runtime compile for
us and just execute as machine code. Just two more concepts to we start the how we inject code in zygotei. We have the nature bridge on Android. Uh nature bridge is just a architecture translator. So imagine we have a x86 computer and we want to run an emulator or Android emulator. We can use nature bridge to understand how the x86 uh op codes will run on ARM. Uh this is start on Android 5 and native breed is really interesting because it executes inside zygote if we don't need the nature breed like if you have a arm device or uh you have an arming device and this will run ARM code uh you don't need the nature
bridge so this unloads from the zygote all Androids uh all the architectures have the nature bridge so okay start on Android 5 And like I said if no needed this will be unloaded. Here we have a diagram I think will be a little bit smaller but we you can check on Hakai offensive security GitHub after this uh presentation. Uh but is what I explained before the all the processes need to read unload and load into the go and check if we will need to translate some architecture codes from the process. we have PLT. PLT is pro table. Imagine we have a table with some symbols, some function names and the address. Uh this will be correlated. But if we we can use
this for hook with if we change the address from one symbol to another we will the control flow of the program. We can use like frameworks like X hook or others. Uh and this is a diagram. So imagine we have this table with two symbols, two functions and two addresses. Uh we could change this address for the first and execute when we call barf funk execute funk. So okay we have a line function uh in line hooking uh is other type of hooking but we don't know the symbol name. We just know uh the address of the function and we can pass and we'll patch the three first uh assembly uh op codes. Uh let's
get a diagram. It's more easy to speak. So we have here the original function we can jump for a malicious code and after this malicious code we will jump for the original code. So this is the control the haction of the control flow just with an address. So okay let's talk to talk how we perform zygote injection. Uh we need to change the nature bridge because the nature bridge will load inside the zygote. We can drop uh an artifact to the first thing that we load in nature bridge is just a loader. This is because like I said if no need to run the nature bridge the code will be unloaded. So we need to drop a new code in memory. uh
and we can restart the nature bridge the original if some application like if you are in an emulator probably we will need the nature bridge the original nature bridge functions we can after hook the P for the class con intern functions uh where this class is the is the place to find the functions like native xxx specialized and on this function we can find where each type of process will be generated will be forked and specialized it uh and then we can have fun. So this is the diagram we will see in a minute all of this but it's the same process that frameworks like GDS and the heru uh does uh and just a quick uh we have hero and
gisk the difference is here as my disk module for Lego injection is up to 11 version of Android uh and is deprecated now because have some incompatibilities with other modules uh we have a gisk h is heru recommends you to use gisk because built into magisto don't have the incompatibility uh in the time that we need to execute this injection and works from uh version 12 for nowadays. Okay, we will replicate what these two frameworks will does. So let's talk about Yaga. Yaga is my project to explain to you how Zot injection attack works and how we can hook the interpreter and head the control flow of a single application. You have the care code for the project
and you can check on my GitHub too. So okay the project was set on an emulator Mac OS emulator uh and on Android 12. Um so first of all what is magis just a simple concept we have a systemless hooting hood binary that is systemless don't change the /s system partition and the most interesting thing around magisk as this can run custom code this can run an extension for its properties here is the face of magisk and we need to develop a magisk module uh a magisk module We have some files like module prop to store metadata or install.sh to enable the features of the magisk module and what we are really interested is on post
fs data. Post fs data will execute this script during the boot process of Android. Uh we have ser surf.sh that will run after the boot process. Uh and we have two these two folders. We have this disk if you want to uh inject some code into the zygote process. We will replicate that. We don't will use the disk folder. We have the system folders for replicate the file system like you have the / system. If you want to place something that will be native on the system of Android, we can place on this folder. And we have the SE policy road that we can edit the SA policy Linux to be more permissive. Uh this is the
module. we need to put this folders like meta in common google android and the two scripts that will identify this is a magisk module. Uh and here on the system folder I will place two files inside the library folder for each type of architecture x86 for or x32 uh is the loader and the operator that we'll see in a minute. We have the install and the module prop just for say this is a module and we have the two scripts post SS data and search.sh uh just the metadata with name version and the author of the code. Uh here on install.sh the two flag the boolean flag to set the two scripts and here we have the post fs data that
will run during boot and just what we need to inject code into the zygote is change the property of vicv nature page for the loader. This will automatically load the code into the zygote. But why this works? We can reverse engineering the code of zygotei. So we have the main function and inside this main function going a little bit ahead we find the runtime start. This will be the start of the Android runtime and inside this function this start here we can check the start VM that will start the virtual machine for store some variables and things from the environment. Go inside of it we can already check some flags here. And going a little bit
forward we can find the arrow of nature brid flag that says that if zero means the nature brid is disabled but if not the bridging is only enabled for the zygote. So we can have an idea that this code will run into the zygote. Uh going a little bit further we have the ji create java vm for setting up some virtualization things that we need to run the code to the interruption. So we have this function inside we have the runtime create and inside we have the instance knit and inside this function of initialization of the runtime we can go a little bit further and find this comment that the Android developers put inside here that
the code will look for the nature breed and check from this control flow and we can find some uh zy goat mentions here. So we can get this idea. Uh and here we have the load of the nature inside the zygote. And here we have the function to load nature bridge. So okay uh if you want to masquerate the the thing the the malicious activity you can put the nature bridge as zero. This just work for like ARM ARM 64 ARM devices because if you need translation you can put like just a new string. And here we have the loader. We place this structure that this structure is just a pointer for the other pointers
that will be replicated from the Android search. Uh this is for just restore the original nature bridge and restore after uh and onload our library our loader. We can check if we are into the zygote process uh drop a new code on memory that will be operator and after that we can just store the original nature bridge with the pointer and the structure. Okay, the function is I go. We can just get the /ro/ self the line to get the name of the process and check if with er into zote. Uh the checks are just to close the library when it will be unloaded if not needed. And what we can do now we can have the Android runtime
code the liroid runtime. So that have some functions like native fork and specialized native fork system server or native specialized process that is the specialization process of each type of process. Uh we have the Android internaliz that will be geni uh raster for each function and here just an example of execution of each type of fork and we have a lot of parameters that will be uh interesting for us. So inside the operator we can do a PLT hook. I use here X hook for the hster native methods and know when a geni method will be h on the process. So here are just some macros and on our hooket function we will check if is on the
classical internaliz and check if the method name is one of the fork types like specialize specialize a process or system server the native fork can specialize for web views I go we can check the signature too just to don't have problems uh like uh Samsung Motorola likes to change this signature they like to do by their selfies. But inside of each condition, we can store a pointer for the original method and [snorts] uh hash use the hash native methods to hester a new function, our function to head to the control flow based on the hashster uh address that will be done. Uh here just the variables that we store the original address and here the signature and the
our new function prototype. We have uh the others functions the other types of specialization and here we have an example of execution. So we can execute normally here by the pointer and we can run a code on prever version that this pre version will execute before we set the specialization before the Linux policy was be applied to this process and we can execute a post that the sea policy Linux measures are being applied already. So we have the both types. We have the others like system server and we have the app process too. On app process I place here for we log the name of the pro that the code will be injected. And here we have a little
demo. Let me put here just make a better a better quality. I hope you can see all. So, okay. Uh, I place a setup.sh on the project if you want to build more easily and you just need to push into your device via ADBD [snorts] and you can install via magisk uh the module and what you need now is just reboot your device because when we reboot the all the injection will be applied on the initialization process. So here we can get the PD of zygotei here. Let's just wait. Here we have the PD 334 for zygote process on this time and we can check a lot of logs coming in and the first log is just code loaded in
zygote process PD334. So we successfully injected code inside zygote and we can see to a lot of logs like uh camera contacts these are the process being generated we are injecting code in each process that it will be open so it's nice so if I open some new process like chrome like uh if I open like my application here dummy tree I can see a new log here calling dummy tree so we have the injected code on this new application that we open now via the zygote. Okay, cool. What we can do with it? Uh we have the libar.so uh that is be that is the interpreter. Uh and we have this code of this
application is a demo application that we have like is root function returning true and displaying on the screen remembering this is a dex code. Uh this will be interpreted. So libero so the interpreter have this function called do call. Do call is the function that execute the method. Uh and it receives the first parameter as an art method. Art method is a class. Here we receive a pointer for the method and art method have this class and some parameters on protected part of the code that have like the claring class uh the method index all the things where this method is located and need to be executed. But the most important thing is the entry
point from quick compiled code that will be the address for this function. We have inside the art method to this function that is pretty method just returns a human readable something like a package package the class that will be located and the method name. Okay. So what we can do with it? We have the app process post version that's the SA plus Linux measures are being applied. Uh and we have two variables here. We can get the package name Charles from nice name and the app. This is just the name of the process and the / data/ data of the application. And we can check if the process name is the same as the application name. And
here all this coding this condition will run inside just of this application. So we have some cache for uh the Java VM and the data JS. We will see this in a minute have just the function to get the M and get some variables inside the runtime. And here we can hook the first function from libart the pretty method. And we it's a little bit difficult to get this address. We need to self-implement a way to get the address like find name. I will s uh look show to you in a minute and we can use like Dolby is in line hooker you we get the address of the function and we just use this address to
hook this function. So pretty method we will execute normally we just need the original implementation and here we have the find name function. The find name function we need to follow some steps like we need to load the memory map the virtual memory map of the process find the library name and get each page and when we get these pages we can reconstruct a L file and check by uh the sections the dynamic symbols and the static symbols and look for the symbol that we want and restore each address. So each function we load the memory map from the prox of maps. Um we can get each uh page and we can reconstruct after we find the library
name we will reconstruct this inside memory. So here is just the reconstruction and we have the do load function and this do load will just load the elf will get the magic bytes and reconstruct all sections in memory. That's just it. Uh and we have the get symbols. Here we get the static symbols and the dynamic symbols like uh we have the lookup sim function and this we will just after we reconstruct the file and can get the symbols we go in the sections that have the dynamic symbols and the stack symbols and get all this stuff. Okay. uh just some structures that I use it like to get the static symbols and dynamic symbols. This is the symbol tab.
Uh and to get the memory map and okay, we can do this for do call. Uh the do call function have four variations. We need to hook all of them and we can pass just an intereration to the same function. uh the what we need to do after hooking this function is every the same. So okay just some code stuff for hijack for this function. Uh this function is the hook to call and inside the call we have the art method and if uh with the art method we can call pretty method calling pretty method we can have the name of the function the class that is being executed on this moment. We can check if this is from com
example tree is the name of my application and we will know that this the package of the execution of this function is the our application itself not like the Java runtime function. Uh and we can log to have a like a stack trace of all the functions that were called. uh and we can check if is this root function inside the main activity class and if is we can get the M load a new dex into memory get this method transform into J object and get this art method and if it's is root function we don't need to execute normally the original function with arg one we can just place the new art method that we
load into memory so this is the just our replicate for art method And here we have the load dex and get method. Uh we will load the myex.ex file inside the / data/ data of this process. Remembering that we need to pass a execution read and write uh permissions. Uh we need to get the J object. We need to get the art method of this J object. And just remembering we have the this function as example is root returning true and we can patch this function changing the dex for zero this mali that will be converted for dex in a new class called my dex uh this is the resulting java like uh we have the false
uh and here is just the process to generate these decks. You can find this on my GitHub project too. Uh, and let's go for the demonstration. So, let me just put on a better quality too. Okay. Uh, first of all, we have this function. I hope you can see you can see pretty well this the text. We have the true value on the screen and here we have is root function and okay we just need to compile our module with sets script and pass to the device install the the magisk module and reboot our device and when it reboot we'll be apply all the modifications Just a minute. Here we can see all the logs coming in and the the code being
injected. But when we open lip gum tree, we can saw the string now is false. And here we have all the stack trace of all the functions that were called and what function were was patch patched. So pretty cool. And we have a dex code hooking now via ziggote. Okay. Uh written on the code we have this native code too string from native code that comes from libmetry.so. Uh remembering this is a machine code in dynamic library format. Uh here we have on the compiler that we have the returning of hello from nature breed string from this function. But if we pass a new argument, this will pass here and return this new string. We can hook this from linker binary or
libdl.so. But linker binary on Android uh use libdl.so. So I prefer going on this way and get the Android open xt. Um and we can hook with Android open xt. You can hook with X hook too but I prefer Adobe on this case uh because we can pass a new pointer here and he will find the library. We don't need to specify a library and when we hook we can check on the first parameter if the library name is libmetry. So execute it normally the Android the open x and get a handle and get the address of the symbol of a string from native code and hook this native code. Uh here we have the new function. We
generate a string called hacket and interpreter the cast for int 64. That's the same that we saw into the the compiler here.
And that's it. So let's check it out. Uh let's just pify the video. Okay. So when we open the application now we can see two strings true and hello from native code. This is the original behavior. And we can do all the same process just set up push the device the module and install. I'll just skip to get more time and we can reboot the device. And after we reboot the device, we can see the injection of our process here. And when we open now the same application, we can see the string true, the string false, sorry, and hacked and all the tech traces of each method and each library. So pretty cool. We have
two injections, two type of injections, the interpreted code and the machine code. Uh so let's call about and talk about Lihoo. Lihu is just a partnering of this project for JISK. So we don't need to care about zygote injection more just the hooking of the all the methods the application methods and here we have the care code if you want to check the project and that's it this working more versions of Android I think uh version 11 12 and 13. Yeah. uh feel free to contribute with this project, send requests and other things. Uh okay. Uh imagine that we have an application that have a lot of protections like the bug detection, ADB protection, emulator
and JWP. uh some protections in native code and some protections index code like I came later to get a dynamic text or check if the application has been debugged. Here we have the implementation of like the adv detection and the take actions. The take actions just will they have a new pointer to crash the application itself uh and take the measures. And we have like the JDWP uh detection to check if we have the flag on prox of tasks. And here is how you use Lihoo. uh you just need to change on post app specialize some functions like set app set set abk name and place your appk name and you can choose like hster dex
hook or hester native hook uh if you have a native function you can pass where what library it's located the entire name of the function and create a pointer for a new function and a pointer to store the original pointer of the function and for a dex hook We can pass the package, the class and the function name of the original implementation and now separated the new class, the new method, the signature of the functions and what is the dex that will be located. Uh these decks need to be placed at / data/ local/temp. Uh here we have the implementation for the native code. We have the turn zero hit turn zero for both protections for
hit turn false and we have here from the decks we generate a dex like bypass deck with zero and zero for the protections and a dynamic text call it hacked. So let's go to a demo. Uh I will put just on a higher quality and okay imagine that we have the application. We open the application and boom it's crashed because we have a debugger detection. How we can bypass it? We can just build the lehoo project have a setup script too. Uh and you can push the module lehu magistic module.zip inside the Android device and you can push the bypass dex to/ data/lote 2. Uh, we can install daily module. It's just a cat. I love cats.
And we reboot the device to apply all the all the injections. Remembering that the jisk on my disk needs to be uh enabled because if want we will not uh be able to disexecute. So enable jisk before it. You can place interesting thing you can place the with the JISK an app on the n list. So we can bypass root and hook the application with this framework. So really cool. Uh so when the device starts we won't see any log just when we open the application that we are targeting and the same application now will show the string hacket no will crash and we can see all the stack traces stack traces for the functions that uh were being
executed that the program expect to be executed and what functions we patch it to bypass it. So we have really secures and if we will bypass some protections like H has protections uh runtime applications have protection you can look all the stress of the application before you know like whoa this function is what uh kill the application now and you can patch this. So what to do? Uh the only thing that is missing now that I see is static methods on Dex code because the stat the method that is static on DEX code is a little bit different. It's pretty the same but it's a little bit different. Uh but for all the other DEX methods and for native
methods already works. So that's it. Feel free to contribute with the project. Uh here is the biography uh questions and if you you have no questions I will just place a thanks and redirect to you for the care code of Hakai security. Uh and that's it. So feel free to ask some questions and that's it. [applause]
Okay. Got it.
>> No.
>> Is that on? >> All right. Uh, so I'll just be loud without a microphone. Uh, first question. If native bridge is it is not enabled for example if we're not in the Android code none of this works right uh Android code we load native breed uh you don't like if suppose that Google ships a version of Android or devices that does not contain the native bridge functional >> yeah if the if the Android code remove the native bridge like uh you'll get the source codes from Android and remove no need but for default the native code will load if you want >> what >> by default of course they ship it but if that functionality wasn't there then you
basically wouldn't be actually >> yeah if you remove yes and but if it's just that if it's place it that you just get the original code is by default >> okay >> like that >> why in the world does Android ship on devices with that functionality? Is there any practical reason for it? >> Uh, it's a great question. I think is because the I don't know if older versions of Android were other architectures before, but nowadays no need just for emulators. It's really strange. >> Yeah. Yeah. I mean, it would seem that they would they should just ship a version for emulators only and maybe developer mode and call it. Good. Okay. Uh, second question. I don't believe you
really like cats because there wasn't a single cat picture in your >> No, I love cats. >> So, uh, >> okay, good. Thanks. >> Hey, thanks again. Um, were you able to see if Google Play Protect could you completely defeat all the checks in Google Play Protect? You can ex just a little bit lower. >> Oh, did you try an app that uses Google Play Protect and see if all of your uh measures could defeat? >> Yeah, on Google Play Protects it bypass because the Google Play Protection just check the signature. If you patch the code like uh if I decompile the application, change the code and rerun this will protect on the Google Play uh
version of protection. But on dynamic uh bypassing, no, these don't check. >> Yeah. >> Okay. Cuz as far as I remember, Google Play Protect does more than just signature checks. It'll try to see if the device is rooted and things like that. >> A little bit slow. >> Oh, I thought Google Play Protect uh also checks if the device is rooted and some of those other heruristics that you could patch.
against >> yeah I don't understand the the end but is like that the the static version of patching no but uh the the pl checks just the static not the dynamic version if we you can place a dynamic protection by yourself but Google don't do I think his question was just have you uh tested it under those circumstances? Uh have you tried to run any of this code through something like the Google Play Store and those checks and seen whether >> you can just talk a little bit? I don't know why it's a little bit >> not that obvious. It's just a very close proximity effect. Mike, um have you tried testing it against those
scenarios? >> Yeah. Okay. I tested and it was able to bypass that. Yeah. Was able to bypass. >> And your theory to this is this. If you're doing this dynamically, there's not enough there to Okay. >> All right.
>> Okay. I think no more questions. Someone. Okay. So, that's it guys. Thanks for watching.