We have a uh super interesting talk for you up next by um Omro Abdel-Gawad. Uh he's a security researcher with Immui or Immuni sorry uh my words speech is getting a little slurred today. I'm not even drunk. So uh without further ado uh I'm going to let him take off his talk. Let's get a big round of applause for him. So when I started working on the remote metamorphic engine research the last thing I was thinking about back then was metamorphism. Alright is it okay now? So the last thing I was thinking about when I started working on the remote metamorphic engine research was metamorphism. I wasn't thinking about metamorphic at all. I was mainly trying to create unbreakable code. A piece of code that cannot be reverse engineered, cannot be tampered, cannot be analyzed. So anyone who has limited experience with reverse engineering will know that it's actually not possible to create unbreakable code. It's possible to resist reverse engineering but it's really impossible to create a piece of code that would have high resistance to the degree that it cannot be analyzed. So I researched the I researched the subject. I read about a lot of papers. I learned about a lot of obfuscation techniques. Amazing obfuscation techniques and I applied a lot of techniques. But unfortunately I failed. Sequence of failure attempts kept going up until the moment that I decided to simplify the problem and treat the problem as a security problem. Well at first that actually turned to complicate the problem rather than simplifying it because unfortunately we don't know what security is. You know we know what security is not and we learn about weaknesses based on knowledge of vulnerabilities and we learn about strengths and insecurities based on weaknesses and defined weaknesses but we really don't know what security really is. And when I started setting up my first If you asked me 15 years ago when I started my career what is security you would have lost your whole day receiving my response to your question. Today if you ask me the same question you will really make me think. Something amazing about security that the more we learn about it the less likely we are capable to define it. But there's no wonder as at a certain point in my research I came into very satisfying view for security. That security actually meant to be undefined. That security is all about undefined expressions. Undefined expressions that aim to take probabilities out of the equation that you're trying to secure. So the remote metamorphic engine research of resisting reverse engineering started by defining security as an undefined expression. Taking the lessons learned from my research I came to the conclusion that security and learned from there and applied to the binary protection problem and that resulted in pflux binary mutation. And only then with pflux binary mutation I started to have satisfied results for resisting reverse engineering. But resisting reverse engineerative or resisting a reverse reverse engineer turned to be not enough. Once you have high rates of satisfying results of resisting reverse engineering you will then realize that the problem is much bigger than that. You need to also count automated tools, you need to count AI tools or machine learning and you and and then the problem is not only about the code the problem is also about data. How you're going to secure the data input output even the data while it's being processed inside the code. So that resulted in the end by adding techniques to secure the data and the code that resulted in sort of artificial immunity. So that's the outline of the presentation today and the remote metamorphic engine is actually the name that I've given to the approach which is a new approach for resisting reverse engineering but it's it's more like a new approach rather than an actual engine and I decided to name the approach like that. Because it's not possible without metamorphism or mutation and it's not possible without having the engine or the morphic engine isolated remotely or away from the reverse engineering environment. And I'm applying all these techniques using very simple very simple techniques that I'm going to go through it all with you today within the coming few minutes. So I define security as a very simple and very simple expression. It's an undefined expression following very simple analysis flow. If we don't know what security is but we know about a lot of successful security solutions so if we analyze these successful security solutions enough we can then find patterns that keep repeating itself everywhere and then we can by defining these patterns probably that will will help us to better understand security and will help us to better approach security. So that's exactly what I've done. If you ever do that you will find something pretty interesting that randomization and isolation are two major patterns that we rely on in everything. To the degree that if you take these two patterns out of the equation or out of any security solution security is not going to be possible. Randomization like let me give you an example like stack buffer of protection where we insert random number and then we check on the random number when the function returns. Address space layout randomization to disable jumping into hard coded uh locations. Encryption uh asymmetric um asymmetric and symmetric encryption almost everywhere you will find random numbers without random numbers we cannot apply a lot of security solutions. And on the other hand a much stronger security pattern is isolation. And if you just treat these patterns based on their meaning randomization and isolation you will find that the patterns are not really much different from their meaning. But analyzing them in abstract mathematics you can then be able to isolate the patterns away from their meaning and then you would be able to extend their strength and to find their ultimate strength and then you would be able to move freely with these patterns to apply it on other problems. So I've done just that and then I I arrived into defining randomization in its ultimate security pattern as division by infinity. And then I was able to solve this problem in an inverse relation to probabilities where like you it increase the random number as much as possible to reduce probabilities as much as possible to zero. And on the other hand I defined isolation as a division by zero which is an undefined mathematical expression and by then you can actually take probabilities totally out of the equation. So only then when I return back to solve the binary protection problem only then I started to see another dimension to the problem. From that perspective all the researches that I read about and learned about and all the failure attempt that I went through they were all going toward infinity in an attempt to increase the time and effort needed to disable reverse engineering or to resist reverse engineering. So how about going towards zero? In this scenario in this case instead of increasing the time and effort needed for reverse engineering we will just reduce the time as much as possible to zero. So allow just few milliseconds for the code to be executed. And by that there will be no way for the code to be reverse engineered. Imagine that you are just generating a code that will be valid only for six milliseconds. There will be no way that it will be reverse engineered. Unless it will be saved and then analyzed and then reverse engineered will return back to try to attack the system based on knowledge of previous execution but then if you do that it means that the code is expired. The code is not going to be used anymore so you need to generate new code. And hence we need to have metamorphic engine. But not a metamorphic engine from the perspective of viruses or malware where they use metamorphism just to change the way the code looks like or to change the pattern or to change the signature of the code. We need to have metamorphic engine so that we have actually more like mutation engines more than just ummm. Mo-Morphic engines. So I went by and I defined the unbreakable code as an unpredictable code. But a code that cannot be determined and cannot be and and to keep on changing. Um and it cannot be expected before it gets executed. And while trying to apply this type of algorithm, by the randomization and isolation techniques that we talked about I found that the major weakness is actually the static code dynamic data which is the model that we use to everywhere that this is the way we learn how to program this is the way how we learn how to develop our software. The code is static and the data is dynamic and that that enables all sorts of reverse engineering and also enables all sorts of replicable software exploits. So I tried to change that model into the dynamic code dynamic data that the code will keep on changing and the code will keep on evolving while it's being executed and that the code will not remain the same will not remain static. So if you look at the code now and try to analyze it, it should look totally different than the way it looked just a minute ago or a few seconds ago. So any reverse engineering attempt goes through three main stages. The locating the code, analyzing the code, and then breaking the code. In order to have very high rates of RE resistance we need to resist all these stages. We need to make the code unlocatable so we're gonna make that by storing the code remotely and and and perform remote execution and we're we're gonna disable analyzing the code by using flux binary mutation and by setting the lifetime of the code into a few milliseconds and then we'll make the code unlocatable and then we're gonna make the code unbreakable by allowing the code to know more about itself that it would detect any tampering attempt if any happened while it's being executed. So the remote metamorphic engine architecture looks um as you see here will divide the engine into two separate areas. Trusted area and untrusted area. The trusted zone here is the area where the reverse engineer has no access to. And the untrusted zone is where the reverse engineer would have access to. Um we'll have mutation engine stored in the trusted zone that will keep generating code and keep mutating the code and then push the code to be executed in the uh in the untrusted zone by using challenge response a metamorphic protocol. So why remote? Why we have to store the engine the morphic engine remotely away from the reverse engineer is a reverse engineering environment. Well if you keep the engine next to the in the reverse engineering environment a reverse engineer will just simply go and reverse the engine itself and will break the engine. So in order to secure the engine itself the engine has to be stored in a secure area and an area where the reverse engineer doesn't have any access any access to. But you don't really have to do that. It all comes to what you're trying to defend against. If you are trying to make the code keep morphing itself and keep changing because you're trying to defend against intrusion or malware or um external intrusion. So you can you can then have the the engine in the same trusted area. Uh but today I'm mainly focused on or the presentation is mainly focused on resisting reverse engineering rather than using metamorphism to secure uh the uh trusted environment. So the remote metamorphic engine is a machine that is based in a ll bottom up communication protocol. So the protocol is based on the emission simulation with the request matches one information, the email communication a slight Только the receive the the the code and execute the code and then respond back the respond to the uh to the engine. Uh and it by now is on the And trusted area and untrusted area here can be client and server, it can be kernel and user mood, it can be uh guest and host machine, it can be even like an oil reader in an oil field and then you need to check its integrity to make sure that it's secure, it's not tampered um and on the other hand we also should count the offensive approach which is in in this case a malware can use the trusted area as a command and control server and the untrusted area as the infected machine where it's untrusted because reverse engineers will have access to. So by doing that we would actually split the execution flow into two different areas. An area that the reverse engineer has access to and another area where the reverse engineer doesn't have access to and that on its own would will create a lot of challenges for the reverse engineer because the reverse engineer will never see the whole picture. Will see just you know parts of the code being executed and we didn't even determine what decision is gonna be made on the responses or return values. So here is a list of uh samples of the challenges that can be pushed into that protocol which is mainly here I'm mainly focused on challenges that will check on the integrity of the environment uh such as in memory, code, and the code integrity check. Um execution environment integrity check. Uh detecting hoax or trying to determine if the execution environment is real or it's emulated or it's instrumented. Uh clock synchronization uh uh clock synchronized challenges is actually empty challenges it has no functionality at all where you can just create a challenge that has to be executed to be solved and then you would push it to the untrusted area to make sure that it's not analyzed um and then detect virtual machines or detect um uh or collect hardware um ID's to check on the integrity of the hardware. So once you start to work on these challenges you will find that not all the challenges will have the same strength. Some challenges will be so easy to be broken and some challenges will be much harder to be broken from a reverse engineering perspective. The challenges the the more you're gonna rely on the system the more you're gonna rely on the CPU and the execution and the process itself that you will you will create challenges that will only execute inside the process this will be the uh most the most solid challenges but if you're gonna create challenges that will communicate with the operating system or resolve or communicate with APIs in the system these are weak challenges that can be fooled easily. So that makes the approach if it's gonna be used by any malware will be will be weak enough to be analyzed. The only trick will be just to to know that a malware is analyzing the execution environment while you're analyzing the malware and to make sure that you wouldn't slow down the malware while it's being executed so it will reveal all its functionality and you can go on and um and reveal its functionality. So in order to ensure um in order in order to ensure to secure the challenges we will use um uh morphing techniques where we will have the function that we need to execute and then we have to mutate the function in a manner that the challenge cannot be solved unless the code is executed. And the way we will do that we will have to rely on other morphing techniques not just like the uh malware morphing techniques we need to use mutation techniques that will change the functionality of the code not just changing the code structure or not just the structure of a function but changing the code uh semantics. So here's how we can uh here's here's what how here's how I'm creating these challenges in the remote metamorphic engine is getting the function and then applying morphing techniques on the function changing the function structure totally and then add a head and a tail to the function and the head is just unused instructions and the tail is where we will would perform response mutation. So every time the function is gonna get executed it will return different response. Here is a sample of the code being executed. Challenges are being generated and being sent to be executed in the untrusted area. And as you can see the encrypted response every time the challenge is being executed it will return back different return value and then the morphic engine, morphing engine will, will receive the response and then decrypt it back to its original value. And the main reason why you need to do that is to make sure that no one can fool the responses or can hook into the response and then just uh send fake responses. So in order to perform mutation for every single uh challenge I'm mainly using reversible and instructions and the reversible instruction what they do, what they do is that um when the function returns, before the function returns a set of instructions will take the return value and then mutate the return value. So the remote metamorphic engine will, will generate mutation key and then use that key to create uh dynamic encryption routine and then insert the encryption routine in the end of the function to encrypt, to encrypt the response and then once the response is returned to the remote metamorphic engine the, it will use the same mutation key to use to generate a decryptor that will decrypt the response and return it back to its original value. So here as you can see these are samples of the mutation um that we will use to mutate the response and this mutation is going to be used to decrypt the response. This is actually as you can see here we're using a set of reversible instructions like addition, subtraction, XOR um bit rotation to the left or to the right and then once the response returns back you will apply the opposite um instruction to, to, to um to reverse the, the response back to its original value. So once you start to use these instructions, and as you can see here if you use these instructions in detail any AI or reverse engineer trying to analyze the code will be able to detect that this set of instructions is actually in the tail of the function. So in order to disable that we have to use the same exact instructions in the body of the function. We'll use that in the morphing um um in the morphing techniques that we're gonna do to the function and also we'll use the same instructions in the head where we will insert use lists and instructions. So this, this, this how like anyone analyzing the function will not be able to determine the beginning of or the end or the body of the function. So here after performing the morphing techniques that I'm gonna show you now, what you need to do is to disable any reverse engineer or AI trying to uh automated tools trying to analyze the code you need to disable them from determining the beginning or the end or the middle of the function by mixing the same instructions. Instruction sets everywhere in the function. So the mutation techniques that we will need to use to resist reverse engineering, it's totally different than the mutation techniques or the morphic techniques that malware would use. Malware, they use morphing or polymorphic techniques to evade anti-viruses. They use polymorphic techniques simply by encrypting the code and then when the code executes it will fold memory and then decrypt and then will be in its original form. And on the other hand they use metamorphic techniques to make the code operate in the same exact way but would look totally different and use totally different instruction sets. So no encryption is used in in metamorphism. Here are some samples of what uh here are some techniques that are used by and by by malware uh metam, metamorphic techniques which is like all aiming to change the structure of the code or evading signatures but what we're trying to do here is not really to evade signature, we need actually to resist reverse engineering. If you make some few changes to the code to make it look different, still a reverse engineer can easily determine what's going on. But more importantly, because we need to evade artificial intelligence or any automated tools, we we we need to use morphic, morphing techniques that will make it a more efficient and expensive for automated tools in terms of time rather than just changing the signature. So the flux mutation goals that we're going to have is to extend the trust. So the notion is that if you have few milliseconds of trusted execution, we need to be able to extend that trust from few milliseconds to cover the whole untrusted area by checking on the the entire network. So uh we need to it by checking on the integrity of the execution area. Uh ensure trusted execution we need to make sure that the challenges that we're creating will not be solved unless the code got get executed. And while doing that we also need to disable the code being emulated or instrumented. And we need to also detect reverse engineering or and evade reverse engineering while the code is being executed. So in order to make it expensive for any automated tool or reverse engineer trying to reverse engineer the code we need to have we need to use morphing morphing techniques that will that will require time for any automated tool to analyze the code. So I'm using here mainly structure obfuscation. So every time the code is being morphed the structure of the code is being morphed. So the structure of the code will be totally different. And I'm actually changing the structure of the code not by making the structure look different but actually by making the structure look the same. So all the functions while while they are being morphed though they are different functions at the end they will look all the same. And that's how you can that's how you can make make it harder for any automated tools to determine the difference between the functions. So we'll make it harder for any automated tool to attack the code while it's being executed. So these are actually basic blocks. So we we take a function simple function and then we would morph it into thousands of basic blocks that they all look the same. And these basic blocks will be totally disconnected. There's no edges connecting these basic blocks with one another. And then we will we'll have to use self modifying techniques. Where every single basic block will have its own function. So that as a function of the basic block when the basic block is executed it will modify itself and then connect to the next next block only after it gets executed. So here as you can see reverse engineer will just receive the code as totally disconnected basic blocks and then only when the when when these blocks start to get executed they will start to connect to one another. And that's how we can make it more expensive for any reverse engineer. So thanks to the or automated tool to analyze the code. In order for any automated tool to analyze that code it has to emulate the execution of these basic blocks or analyze it so it will be expensive at the end of the day in terms of time. And then at the end you want to make sure that that in order for the challenges to be solved it will only be solved if the code get executed if the code get executed only natively or even on an emulator but not um on an um instrumentation tool or any tool that tries to understand try to understand the code or break the code while it's being executed. So here sample of these basic blocks. Every basic block here is actually just one instruction and the morphing techniques that I'm using is actually taking the code and I'm actually taking the code and I'm actually taking every single instruction as you can see up here this is the original instruction and then taking the instruction and then transform every single instruction into a basic block. And that basic block will encrypt the instruction and then the only way that the real instruction will appear is by executing the basic block. So this is the basic block. So the morphing techniques that we can use to resist reverse engineering in the context of clock synchronization that you're allowing the code only to execute for few milliseconds is totally different than the morphing techniques that is used by malware to change the structure of the code or to evade signatures. So here is the list of the techniques that I found to be very helpful. We need to use metamorphic techniques plus polymorphic techniques. So we need to use polymorphic techniques. You cannot really rely on metamorphism only. You need to use polymorphic techniques. And why you need to use polymorphic techniques because you have to do self modifying code. You have to generate self modifying code to make it more expensive in terms of time for any automated tool to reverse engineer the code. And you need to make code structure obfuscation so any AI wouldn't determine which function is which because not all the challenges will happen. So you need to use polymorphic techniques to have the same strength. Some challenges will be weak and some challenges will be strong. So you need to disable any reverse engineer to determine which function is which and the way we'll do that is to make all the functions look the same and all the functions will have the same structure as I showed you. And then challenge response mutation which we talked about in the beginning is that we need to you're generating code that will expire in few milliseconds so you need to actually make the code function differently. Because if it wouldn't function different differently it can easily be faked. So every time we execute the function it should function different way and return different return value. So it will uh transform into a real challenge. And slices permutation is where if you have 100 functions if you send these functions to be executed in the same sequence that will be a weakness as well. You have to morph the sequence of the functions. So make sure that the code size is equal. Every time you send functions to to be uh executed you will have to rearrange the sequence of these functions while being executed. And code size magnification is also very important here because if you're expiring the code in few milliseconds and you're trying to determine if the code is is being executed natively or if the code is being analyzed if you're sending just few instructions it will be so hard for you to determine the difference. So you have to magnify the code. You have to magnify it enough that will enable you to determine or you will have uh larger difference between if the code is being executed natively or the code is being emulated. And by saying emulated here I don't really mean like emulated CPU but rather instrumentation. Like the code is being instrumented while it's being executed and then a reverse engineer or an AI would patch or like would uh tamper the code while it's being executed. And then you have to make sure that the code is being executed. So here's a sample. This is just a very simple function that you can define in the remote metamorphic engine. This function is just checking if the debugger is connected to the process. And I've chosen this function because it's just very short and small and enough to fit into the screen. So we'll start morphic techniques by inserting useless instructions, unused instructions. And then we can see that the code is being executed. And then after inserting these unused instructions and randomizing uh every time you would insert different set of instructions this is how you can change the a little bit the structure of the code on the first stage. And then here we're also can use expansion so you can replace one instruction that does memory operation you can change it with a different set of instructions that perform the same exact operation but in a different way and using different instructions. So the the first morphing stage you will reach uh that code. And then in the second morphing stage because we need to make it harder for any reverse engineer to analyze the code we need actually to tr- change the structure of the code and make it much harder for any automated tool. To hook into any part of the code so every single instruction should look totally different and should and should be moved into totally different position inside the function or inside the binary code. So what I'm doing here is actually I'm taking that code and then inserting a label into every single instruction and then inserting a jump after every single instruction. And by that I'm totally free to move any instruction anywhere. Because the sequence of execution will always be the same. So this code here that you see is exactly the same as that one. By inserting labels and inserting jumps after every instruction to the next one, you are free to move any instruction anywhere. Or you are free to move any of these basic blocks anywhere. These two are exactly the same. Just doing trans trans transposition here. So after doing that and changing the structure of the code and doing transposition and push it moving every single instruction in a different uh location we will take every single basic block and then use polymorphic techniques to transform this basic block into self modifying code. So that basic block we're gonna take it and transform it into that morphed basic block which is a self modifying basic block. As you can see here this is a mutation, a randomly generated mutation key that I'm using to create randomly encryption and decryption routines. And here as you can see this is a randomly generated self modifying code so every single basic block which is actually every single instruction will be transformed into a self modifying code. So every single basic block which is actually every single instruction will be transformed into a self modifying basic block on its own. And here is a hel- helper function that just helps to allocate the location of the code in memory. And as you can see these parts actually will transform into self modifying and it will modify itself while it's being executed to um um to unfold into the original instruction or the original basic block. So that's a basic block. And also the jump that you see here, the jump that is after the instruction is also gonna be morphed so any AI or reverse engineer trying to understand what, which instruction will be next he wouldn't be able to know or any automated tool trying to analyze the code they wouldn't be able to know which next instruction, which instruction will be next until the code is executed and the code self modify and decrypt itself and then we'll jump to the next, the next instruction. basic block and then the next basic block will self modify and decrypt itself in memory and then will reveal the next instruction and so on. And we need to do that because we only have few milliseconds for the code to be executed and we want to make it very expensive for any automated tool to try to solve the code within that allowed time frame. Like these techniques might not be that interesting if if you just give the reverse engineer as much time as you want to reverse engineer the code but in the context of the code has to be executed in a few milliseconds these techniques are very helpful and for sure it's going to be helpful if you want to add if you would add multiple layers of self modifying. So at the end you will the code will be morphed into these structures here as you can see these are like three basic blocks so every single instruction will be transformed into these randomly generated blocks. Here's a sample of the code being executed and self modifying just to give you a feel. All the basic blocks they will end up looking exactly the same and while being executed they will change and they will connect and they will un- unfold in memory. So this is the basic blocks that we are going to be using in the next few minutes. So let's go ahead and see how this works. As you can see here this code will change now and unveil un-reveal that instruction. Sorry. So these morphing techniques if it's used normally you know to just to morph a piece of code it will then be helpful at all but the point is that the code will have only few milliseconds to be executed and to respond back to the remote metamorphic engine with the right response. So here as you can see these are four different generation four different samples of the same function being morphed and every time the function is morphed. return value and then the engine will receive the return value and then decrypt it and return it back to its original value and as you can see here the response time is 6 milliseconds. I was here connecting the trusted and untrusted area the remote metamorphic engine and the and the client on a same machine in a local local host if you're gonna connect it remotely it might be much longer than that. And here as you can see every time the code is being morphed it will it will be um it will it will result in a totally different code size so the code size will be different the structure will be different and the instruction sets that are used will be totally different as you can see the first time it the original code actually if you if you just assemble it it will be around maybe 30 or 40 bytes and here these 30 40 bytes of the original code are being transformed into 15,000 bytes or around like 2,000 or 5,000 5 or 6,000 instructions. Now in order to determine if the code is being really executed or if if the if the challenge really been solved without being tampered or without being reverse engineered or without being emulated or instrumented. If someone just hooked into the challenge response protocol and then tried to just set the return value into any value and trying to fool the protocol um the remote metamorphic engine can easily detect that. So any any any immunity system in nature actually is based on knowing the self. So the remote metamorphic engine actually tries to detect the function that will actually run within the command midивare eres. And if the the instruction some other function that will not be executed nuestra kh recomendation to use what is present timeogo they apply this function every time I go on to inside A plan, I would use a synchronguer to show what are the incoming and Shall I give it to him um I would use notwait James Theo again because probably the reason why you did that was that didnst the engine will use the the randomly generated decrypt decryption or mutation key to solve the challenge and return it back to the original value. So as you can see here if anyone tries to tamper the code while it's being while it's being executed or try to tamper the response while the response is being returned by just simply hooking into the response and then sending faking the response the engine can easily determine that by comparing the responses with the previously returned responses. So as you can see here these are seven different mutated functions of the same exact functions. Every time the function is being sent to be executed it will return back totally different value. And then all these values should decrypt back to the same exact value. So the remote metamorphic engine can determine if there's any tampering attempts if the decrypted value will look totally different or result in a different value than all the previously generated code. On the other hand the engine can be able to determine if the the code been executed natively or in a healthy way compared to being instrumented or being analyzed based on time. So we in in this challenges for example we're allowing 500 milliseconds for the code to be executed and to return back. And then the engine can determine if the code is being analyzed or the code is being emulated or being instrumented if the response returns back in a higher time frame. So the way I actually set the allowed time frame I'm actually doing it manually by executing the code natively and then measuring the code the execution time of the code. And then with allow because every time you send the code to be executed it will return back in a different time frame. So you have to enable um a time frame because the code will all will keep on fluctuating. Um so I'm mainly allowing the average of the execution time multiplied by three to five factors. And this way it's like it's based on the assumption that if the code is being analyzed there must be at least two or three instructions being inserted to analyze the code. Uh or there must be at least comparison instructions. So as you can see here uh on the GameCube um the code is being slaughtered in different uh ways so the code has been skewed back and then this is a very complicated and very complicated configuration and this is really simple and easy to use. You are just asked to use the code with different functions. Now the second one we'll talk about is uh another example of um not the model we're talking about but the code that we're using here. But these are from the first generation and the second one we'll all be looking at is uh similar to the old model of uh the old model of the code to be executed. analyzed and then it can uh act in a different way. In case of a malware using these techniques perhaps that would be the most tricky part of it. You know a malware wouldn't really be able to uh change the behavior because the malware will still have to communicate with API, it will still have to communicate with the operating system so still you can determine or you can signature the the malware based on behavior analysis but the tricky part is that the malware can be analyzing the code or analyzing the reverse engineer while the reverse engineer is analyzing the code or the malware can analyze the execution or the instrumentation environment while the instrumentation environment is analyzing the malware so that might eliminate or it's just the tricky part you know once you know about it it's gonna be so easy to bypass it but if you don't know about it a malware can evade and um evade the analysis and maybe act in a totally different way and in this case the functionality is even not stored in the executable file that you're analyzing all the functionalities are stored remotely and then you wouldn't be able to go to the next step in analyzing the code. So it's it's just this trick you know that the malware can use to evade reverse engineering so it's the technique is not really that um uh wouldn't really add much you know to the malware evading malware as much as it can be used for um defensive approaches trying to eliminate the code from being reverse engineered or pushing integrity checking functions to check on the integrity of the code or the integrity of the environment you're executing the code in. And this is actually the most um this is the most challenging part because the integrity of the code is the best thing you can do. The third part is that how can you really trust in any nodes that you are connecting to how can you trust on the integrity of things in your network? How can you trust the integrity of the processes that are running in your network where you are relying on static code? If you're relying on static code and that static code can be hooked can be patched can be tampered in memory and then you wouldn't really be able to determine trust it's input or output. So the remote metamorphic engine can be used to check on the integrity of connected things and to ensure that things cannot be reverse engineered or it will be much harder to be reverse engineered um or or get tampered. On the other hand execution time also you can determine that the code is being analyzed or the code is being faked if the response returned back in a lower time frame than the allowed time frame. In this case maybe someone is trying to fake the responses and executing it in a much faster CPU or performing any tampering attempts that would result in the code being returned very fast. So these two variants would help a lot to determine if the code is being executed natively or it's being tampered or it's being uh reverse engineered. So I'm running out of time so if you have any question you can feel free to email me I'm gonna be using this email address for the coming couple of weeks and uh with that it's been an honor to be part of your day today. Thank you for joining me and have a good day. Thank you.