The Remote Metamorphic Engine
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Abdelgawad, Amro
As a matter of fact, it is all about time to reverse engineer the most complex piece of code. Code complicity techniques are usually used just to increase the time and effort needed for reverse engineering. The desired effect of code complicity can be magnified using mechanisms that decrease and narrow the allowed time frame for any reverse engineering attempt into few milliseconds. Such approach can be applied using a metamorphic engine that is aware of the time dimension. Beyond metamorphic applications for AV evasion, in this talk, we will present a novel approach to resist and evade reverse engineering using a remote metamorphic engine that generates diversified morphed machine code of a very short expiration lifetime. Our approach is based on a client-server model using challenge-response communication protocol made of morphed machine code rather than data. We will show how any reverse engineering attempt on such model will be forced to execute or emulate the morphed code. Thus the code will always have an upper hand to detect, evade and attack the reverse engineering environment. Our approach is immune to static code analysis as the functionalities and the communication protocol used are dynamically diversified remotely and do not exist in packed executable files. On the other hand, clock synchronized morphed machine code driven by a remote metamorphic engine would trap dynamic RE attempts in the maze of metamorphism. One that is immune to code tampering and reversing by detecting the non-self. We will present the fundamental difference between metamorphic and polymorphic techniques used to evade AV compared to the ones that can be used to resist RE. We will show how a remote diversified metamorphic self-modifying code with a very short expiration lifetime can detect, evade, and resist any code analysis, reverse engineering, machine learning and tampering attempts. Bio: Amor Abdelgawad is a security researcher and the founder of Immuneye. He has more than 15 years experience in software security and reverse engineering. He has experienced both sides of software security in vulnerability researching, penetration testing, reverse engineering, exploit development and the defensive side as a chief security officer for software companies running wide infrastructures. Amor is currently working as a security researcher where his main interests are analyzing malware, vulnerability researching and developing artificial software immunity.
 We have a super interesting talk for you up next by Amro Abdelgawad. He's a security researcher with Immunai. Sorry, my speech is getting a little slurred today. I'm not even drunk. So without further ado, 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. 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 subject. I read about a lot of papers and 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. We know what security is not, and we learn about weaknesses based on knowledge of vulnerabilities, and we learn about strengths and security based on weaknesses and defined weaknesses, but we really don't know what security really is. 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 is no wonder. As at a certain point in my research, I came into a 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 there and applied to the binary protection problem, and that resulted in flux binary mutation. And only then with flux binary mutation, I started to have satisfying results for resisting reverse engineering. But resisting reverse engineering or resisting reverse engineering 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 then the problem is not only about the code, the problem is also about data. How are we going to secure the data, input, output, even the data is 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 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 with all with you today within the coming few minutes. So I define security as 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 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. The 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 fruit protection where we insert random number and then we check on the random number when the function returns. And then we add this space layout randomization to disable jumping into hard coded locations, encryption, asymmetric, 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 wouldn't really gain much 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 will be able to move freely with these patterns to apply it on other problems. So I've done just that and then I arrived into defining randomization in its ultimate security pattern as division by infinity in an inverse relation to probabilities where like you 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 toward zero? 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 engineer 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 actually more like mutation engines more than just morphic engines. So I went by and I defined the unbreakable code as an unpredictable code, but the code that cannot be determined and cannot be and will keep on changing and it cannot be expected before it gets executed. And while trying to apply 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. This is the way we learn how to program. This is the way we learn how to develop our software. The code is static and the data is dynamic and 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 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, 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 going to make that by storing the code remotely and perform remote execution. And we're going to 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 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, 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. 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 untrusted zone by using challenge response metamorphic protocol. So why remote? Why we have to store the engine, the morphic engine remotely away from the reverse engineering environment? Well, if you keep the engine next to the interverse 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 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 external intrusion, so you can then have the engine in the same trusted area. But today I'm mainly focused on or the presentation is mainly focused on resisting reverse engineering rather than using metamorphism to secure the trusted environment. So the remote metamorphic engine is based on challenge response protocol, challenge response communication protocol that is made of morphed machine code rather than data. And the protocol is pretty simple is that the trusted area will push four bytes of code size and then will push the morphed code and then the untrusted area will just receive the code and execute the code and then respond back, respond to the engine. And trusted area and untrusted area here can be client and server. It can be kernel and user mode. It can be 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. And on the other hand, we also should count the offensive approach which is, in this case, a malware can use the trusted area as a command and control server and 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 will create a lot of challenges to any reverse engineer because the reverse engineer will never see the whole picture. He'll see just, you know, parts of the code being executed and it wouldn't even determine what decision is going to be made on the responses or return values. So here is a list of 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 such as in memory code integrity check, execution environment integrity check, detecting hoax or trying to determine if the execution environment is real or it's emulated or it's instrumented. Clock synchronization, 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. And then detect virtual machines or detect or collect hardware, IDs 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 more you're going to rely on the CPU and the execution and the process itself that you will create challenges that will only execute inside the process, this will be the most solid challenges. But if you're going to 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 going to be used by any malware will be weak enough to be analyzed. The only trick will be just 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 reveal its functionality. So in order to ensure, in order to ensure to secure the challenges, we will use 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 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 changing the code semantics. So here's how we can, 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 in instructions and the tail is where we will perform response mutation. So every time the function is going to get executed, it will return different response. Here is the sample of the code being executed. Changes 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 morphing engine 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 send fake responses. So in order to perform mutation for every single challenge, I'm mainly using reversible instructions and the reversible instruction, what they do is that 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 generate mutation key and then use that key to create dynamic encryption routine and then insert the encryption routine in the end of the function to encrypt the response. And then once the response is returned to the remote metamorphic engine, it will use the same mutation key 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 that we will use to mutate the response. And this mutation is actually, as you can see here, we're using a set of reversible instructions like addition, subtraction, XOR, bit rotation to the left or to the right. And then once the response returns back, you will apply the opposite instruction to reverse 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 techniques that we're going to do to the function. And also we'll use the same instructions in the head where we will insert useless instructions. So 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 going to show you now, what you need to do is to disable any reverse engineer or AI trying to, 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 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 morphing techniques that malware would use. Malware, they use morphing or polymorphic techniques to evade antiviruses. 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. I use totally different instruction sets. So no encryption is used in metamorphism. Here are some samples of what, here are some techniques that are used by malware, 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 signatures. We need actually to resist reverse engineering. If you make some few changes to the code to make it look different, still reverse engineer can easily determine what's going on. But more importantly, because we need to evade artificial intelligence or any automated tools, we need to use morphic techniques that will make it 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 integrity of the execution area. In short, trusted execution, we need to make sure that the challenges that we're creating will not be solved unless the code 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 an 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 morphic techniques 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 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 they are being morphed, though they are different functions, at the end they will look all the same. And that's how you can 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 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 have to use self-modifying techniques where every single basic block, when the basic block is executed, it will modify itself and then connect to the 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 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 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 in order for the challenges to be solved, it will only be solved if the code gets executed only natively or even on an emulator but not on an 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 morphic techniques that I'm using is 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 the morphic 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 a few milliseconds is totally different than the morphic 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. You need to use metamorphic techniques plus polymorphic techniques. You cannot really rely on metamorphism only. You need to use polymorphic techniques. 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 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 function look the same. And all the function 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 differently, it can easily be faked. So every time we execute the function, it should function in a different way and return different, return value. So it will transform into a real challenge. And slices permutation is where if you have 100 functions, if you send a code to a different function, 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 every time you send functions to be 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 being executed natively or the code is being analyzed, if you're sending just a 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 a 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, that the code is being instrumented while it's being executed. And then a reverse engineer or an AI would patch or like would tamper the code while it's 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 after inserting these unused instructions and randomizing, every time you would insert different set of instructions, this is how you can change 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 first morphing stage, you will reach 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 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 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. You are free to move any of these basic blocks anywhere. These two are exactly the same. Just doing trun position here. So after doing that and changing the structure of the code and doing transposition and moving every single instruction in a different 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 going to 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 basic block on its own. And here is a helper function that just helps to allocate the location of the code and 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 unfold into the original instruction or the original basic block. And also the jump that you see here, the jump that is after the instruction is also going to be morphed. So any AI or reverse engineer trying to understand 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 instruction, which instruction will be next until the code is executed and the code self-modify and decrypt itself and then will jump to the next 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 you just give the reverse engineer as much time as he want to reverse engineer the code. But in the context of the code has to be executed in 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 basic blocks. Here is 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 unfold the memory. As you can see here this code will change now and reveal that instruction. So these morphic techniques if it's used normally to just to morph a piece of code it wouldn't 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 it will respond back with a totally different 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 six milliseconds. I was here connecting the trusted and untrusted area, the remote metamorphic engine and the client on the same machine and the local host. If you're going to 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 be, 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 the original code actually 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 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 the remote metamorphic engine can easily detect that. So any immunity system in nature actually is based on knowing the self. So the remote metamorphic engine actually tries to learn and know about the self by comparing the responses or the challenges that are returned comparing it to the previous execution. So we have the same function. We would execute it maybe five times and every time the code will look different, the structure will look different and the function will actually include totally different functionalities because it's mutated and every time the function get morphed and being sent to be executed it will return a different return value but then the engine will use the randomly generated 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 executed or try to tamper the response while the response is being returned by just simply hooking into a 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 remutably the morphic 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 code being executed natively or in a healthy way compared to being instrumented or being analyzed based on time. So we, in this challenge, 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 than the allowed time frame. So the way I actually said 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 would 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 a time frame because the code will keep on fluctuating. 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 or there must be at least comparison instructions. So as you can see here, these are all the same functions. These are all same generation, seven different generations of the same function. Every time it's being executed it will return back in a slightly different time frame. The first time return back in 45 milliseconds, second one, 65 milliseconds and then in this sample I'm allowing only 500 milliseconds for the code to be executed and then once the return value returns back in a higher time frame the engine can determine that the code is being analyzed and then it can act in a different way. In case of a malware using these techniques perhaps that would be the most tricky part of it. A malware wouldn't really be able to change the behavior because the malware would still have to communicate with API, it still will have to communicate with operating system. So still you can determine or you can signature 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 a tricky part. Once you know about it it's going to be so easy to bypass it but if you don't know about it a malware can evade the analysis and maybe act in a totally different way. 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 just this trick that the malware can use to evade reverse engineering so the technique is not really that wouldn't really add much to malware evading malware as much as it can be used for 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, this is the most challenging 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 or trust its 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 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 reverse engineered. So I'm running out of time so if you have any question you can feel free to email me. I'm going to be using this email address for the coming couple of weeks and with that it's been an honor to be part of your day today. Thank you for joining me. Have a good day. Thank you.
 We have a super interesting talk for you up next by Amro Abdelgawad.  He's a security researcher with Immunai.  Sorry, my speech is getting a little slurred today.  I'm not even drunk.  So without further ado, 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.  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 subject.  I read about a lot of papers and 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.  We know what security is not, and we learn about weaknesses based on knowledge of vulnerabilities,  and we learn about strengths and security based on weaknesses and defined weaknesses,  but we really don't know what security really is.  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 is no wonder.  As at a certain point in my research, I came into a 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 there and  applied to the binary protection problem, and that resulted in flux binary mutation.  And only then with flux binary mutation, I started to have satisfying results for resisting  reverse engineering.  But resisting reverse engineering or resisting reverse engineering 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 then the problem is not only about the code, the problem is also about data.  How are we going to secure the data, input, output, even the data is 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 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 with all with you today within the coming few minutes.  So I define security as 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 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.  The 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 fruit protection where  we insert random number and then we check on the random number when the function returns.  And then we add this space layout randomization to disable jumping into hard coded locations,  encryption, asymmetric, 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 wouldn't really gain much 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 will be able to move freely with these patterns  to apply it on other problems.  So I've done just that and then I arrived into defining randomization in its ultimate  security pattern as division by infinity in an inverse relation to probabilities where  like you 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 toward zero?  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 engineer 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 actually more like mutation engines more than just morphic engines.  So I went by and I defined the unbreakable code as an unpredictable code, but the code  that cannot be determined and cannot be and will keep on changing and it cannot be expected  before it gets executed.  And while trying to apply 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.  This is the way we learn how to program.  This is the way we learn how to develop our software.  The code is static and the data is dynamic and 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 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, 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 going to make that by storing the code remotely and perform remote execution.  And we're going to 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 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, 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.  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 untrusted zone by using  challenge response metamorphic protocol.  So why remote?  Why we have to store the engine, the morphic engine remotely away from the reverse engineering  environment?  Well, if you keep the engine next to the interverse 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 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 external intrusion, so you can then have the  engine in the same trusted area.  But today I'm mainly focused on or the presentation is mainly focused on resisting reverse engineering  rather than using metamorphism to secure the trusted environment.  So the remote metamorphic engine is based on challenge response protocol, challenge  response communication protocol that is made of morphed machine code rather than data.  And the protocol is pretty simple is that the trusted area will push four bytes of code  size and then will push the morphed code and then the untrusted area will just receive  the code and execute the code and then respond back, respond to the engine.  And trusted area and untrusted area here can be client and server.  It can be kernel and user mode.  It can be 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.  And on the other hand, we also should count the offensive approach which is, in this case,  a malware can use the trusted area as a command and control server and 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 will create a lot of challenges to any reverse engineer because the reverse  engineer will never see the whole picture.  He'll see just, you know, parts of the code being executed and it wouldn't even determine  what decision is going to be made on the responses or return values.  So here is a list of 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  such as in memory code integrity check, execution environment integrity check, detecting hoax  or trying to determine if the execution environment is real or it's emulated or it's instrumented.  Clock synchronization, 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.  And then detect virtual machines or detect or collect hardware, IDs 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 more you're going to rely on the CPU and the execution and the process  itself that you will create challenges that will only execute inside the process, this  will be the most solid challenges.  But if you're going to 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 going to be used by any malware will be weak enough  to be analyzed.  The only trick will be just 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 reveal its functionality.  So in order to ensure, in order to ensure to secure the challenges, we will use 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 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 changing the code semantics.  So here's how we can, 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 in instructions and the tail is where we will perform response mutation.  So every time the function is going to get executed, it will return different response.  Here is the sample of the code being executed.  Changes 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 morphing engine 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 send fake responses.  So in order to perform mutation for every single challenge, I'm mainly using reversible  instructions and the reversible instruction, what they do is that 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 generate mutation key and then use that key to create  dynamic encryption routine and then insert the encryption routine in the end of the function  to encrypt the response.  And then once the response is returned to the remote metamorphic engine, it will use  the same mutation key 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 that we will use to mutate  the response.  And this mutation is actually, as you can see here, we're using a set of reversible  instructions like addition, subtraction, XOR, bit rotation to the left or to the right.  And then once the response returns back, you will apply the opposite instruction to reverse  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 techniques that we're going to do to the function.  And also we'll use the same instructions in the head where we will insert useless instructions.  So 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 going to show you now, what you need  to do is to disable any reverse engineer or AI trying to, 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 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 morphing techniques that malware would  use.  Malware, they use morphing or polymorphic techniques to evade antiviruses.  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.  I use totally different instruction sets.  So no encryption is used in metamorphism.  Here are some samples of what, here are some techniques that are used by malware, 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 signatures.  We need actually to resist reverse engineering.  If you make some few changes to the code to make it look different, still reverse engineer  can easily determine what's going on.  But more importantly, because we need to evade artificial intelligence or any automated  tools, we need to use morphic techniques that will make it 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 integrity of the execution area.  In short, trusted execution, we need to make sure that the challenges that we're creating  will not be solved unless the code 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 an 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 morphic techniques 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 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 they are being morphed, though they are different functions,  at the end they will look all the same.  And that's how you can 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 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 have to use self-modifying techniques where every single basic block,  when the basic block is executed, it will modify itself and then connect to the 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 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 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 in order for the challenges to be solved,  it will only be solved if the code gets executed only natively or even on an emulator but  not on an 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 morphic techniques that I'm using is 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 the morphic 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 a few milliseconds  is totally different than the morphic 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.  You need to use metamorphic techniques plus polymorphic techniques.  You cannot really rely on metamorphism only.  You need to use polymorphic techniques.  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 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 function look the same.  And all the function 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 differently, it can easily be faked.  So every time we execute the function, it should function in a different way and return  different, return value.  So it will transform into a real challenge.  And slices permutation is where if you have 100 functions, if you send a code to a different  function, 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 every time you send functions to be 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 being executed natively or  the code is being analyzed, if you're sending just a 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 a 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,  that the code is being instrumented while it's being executed.  And then a reverse engineer or an AI would patch or like would tamper the code while it's  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 after inserting these unused instructions and randomizing, every time you would insert  different set of instructions, this is how you can change 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 first morphing stage, you will reach 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 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 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.  You are free to move any of these basic blocks anywhere.  These two are exactly the same.  Just doing trun position here.  So after doing that and changing the structure of the code and doing transposition and moving  every single instruction in a different 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 going to 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 basic block on its own.  And here is a helper function that just helps to allocate the location of the code and 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 unfold into the original instruction or the  original basic block.  And also the jump that you see here, the jump that is after the instruction is also going  to be morphed.  So any AI or reverse engineer trying to understand 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 instruction, which instruction will be next until the code is executed and  the code self-modify and decrypt itself and then will jump to the next 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 you just give the reverse engineer as much  time as he want to reverse engineer the code.  But in the context of the code has to be executed in 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 basic blocks.  Here is 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 unfold the memory.  As you can see here this code will change now and reveal that instruction.  So these morphic techniques if it's used normally to just to morph a piece of code it wouldn't  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 it will respond back with a totally different  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 six milliseconds.  I was here connecting the trusted and untrusted area, the remote metamorphic engine and the  client on the same machine and the local host.  If you're going to 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 be, 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 the original code actually 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 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  the remote metamorphic engine can easily detect that.  So any immunity system in nature actually is based on knowing the self.  So the remote metamorphic engine actually tries to learn and know about the self by  comparing the responses or the challenges that are returned comparing it to the previous  execution.  So we have the same function.  We would execute it maybe five times and every time the code will look different, the structure  will look different and the function will actually include totally different functionalities  because it's mutated and every time the function get morphed and being sent to be executed  it will return a different return value but then the engine will use the randomly generated  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 executed  or try to tamper the response while the response is being returned by just simply hooking into  a 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 remutably the morphic 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 code being executed natively  or in a healthy way compared to being instrumented or being analyzed based on time.  So we, in this challenge, 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 than the allowed time frame.  So the way I actually said 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 would  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 a time frame because the code will keep on fluctuating.  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 or there must be at least comparison instructions.  So as you can see here, these are all the same functions.  These are all same generation, seven different generations of the same function.  Every time it's being executed it will return back in a slightly different time frame.  The first time return back in 45 milliseconds, second one, 65 milliseconds and then in this  sample I'm allowing only 500 milliseconds for the code to be executed and then once  the return value returns back in a higher time frame the engine can determine that the  code is being analyzed and then it can act in a different way.  In case of a malware using these techniques perhaps that would be the most tricky part  of it.  A malware wouldn't really be able to change the behavior because the malware would still  have to communicate with API, it still will have to communicate with operating system.  So still you can determine or you can signature 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 a tricky part.  Once you know about it it's going to be so easy to bypass it but if you don't know about  it a malware can evade the analysis and maybe act in a totally different way.  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 just this trick that the malware can use to evade reverse engineering so the technique  is not really that wouldn't really add much to malware evading malware as much as it can  be used for 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, this is the most challenging 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 or trust its 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 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 reverse engineered.  So I'm running out of time so if you have any question you can feel free to email me.  I'm going to be using this email address for the coming couple of weeks and with that it's  been an honor to be part of your day today.  Thank you for joining me.  Have a good day.  Thank you.
DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_0_863.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_864_1007.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_1008_1079.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_1080_1307.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_1308_2027.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_2028_2099.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_2100_2579.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_2580_3035.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_3036_4439.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_4440_4655.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_4656_5087.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_5088_7643.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_7644_21515.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_21516_25415.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_25416_29087.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_29088_29207.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_29208_29255.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_29256_35723.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_35724_47315.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_47316_47591.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_47592_48167.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_48168_48275.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_48276_49319.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_49320_53363.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_53364_54203.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_54204_54659.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_54660_55823.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_55824_55955.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_55956_56003.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_56004_57383.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_57384_63851.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_63852_64079.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_64080_64379.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_64380_64511.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_64512_64643.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_64644_64715.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_64716_65123.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_65124_65375.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_65376_65435.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_65436_65867.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_65868_66419.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_66420_66719.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_66720_66899.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_66900_67043.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_67044_67307.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_67308_67787.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_67788_68051.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_68052_68111.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_68112_68351.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_68352_68999.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_69000_69095.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_69096_69383.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_69384_71771.png DEF_CON_24_-_Amro_Abdelgawad_-_The_Remote_Metamorphic_Engine_QvxNo9j70DU_71772_72606.png