Skip to main content
Blog

Being Static in a Dynamic World

What is static analysis?

Static analysis is an incredibly powerful tool for code quality and has had a major impact on the security of applications. But what is it? In the most simple of terms, it’s the analysis of the source code of an application. It studies each of the possible routes through an application from inputs to outputs and looks for issues. Issues can range from mallocs without frees, circular references, unchecked inputs being used to create SQL statements, into system calls or buffer overflows. It’s actually a lot more complicated and this wikipedia page has a good breakdown if you’re interested.

Within the Android and iOS world, static analysis is one of the checks that every app goes through when it’s submitted to the Play Store or the App Store and for good reason; it helps make sure that the code submitted is of reasonable standard.

Why do you need static analysis?

If you’re an app developer, why would you need static analysis? Google and Apple seem to have got you covered, right? Well, not really. While it is part of the submission process, it is part of their process, not yours–and it’s looking for the lowest hanging fruit rather than anything in depth. And do you really want your code quality gate to be at the right most part of your pipeline at submission? In a shift left world, being at the right most edge doesn’t sound particularly fun.

OK, so relying on the static analysis that Apple and Google have isn’t the best. I have thousands of unit tests, code coverage of over 90%, hundreds of integration tests, rigorous code reviews and many synthetic tests, so why on earth should I bother with Static Analysis? Well first, congratulations, and I mean that! Building out a robust testing infrastructure is a non-trivial task and definitely a worthwhile one. Still, even with this type of framework, can you guarantee you’re testing all possible control flows? All possible flows through your app? Probably not. Static code analysis can.

How do you go about static analysis?

Now that we understand why there’s a need for this type of analysis, let’s start thinking about how to go about it. First generation of static analysis and still a large amount of the current solutions out there rely on source code. While this might be fine for analysis of certain scenarios, it’s not a particularly effective approach with app development. Why? Because most of that app you’re creating is leveraging SDKs and those SDKs are object code. 40% to 90% of an iOS and Android App is typically composed of SDKs, they’re typically pulled in as object code, and even where there’s source code available, unless you’re compiling that source code as part of your build process, your static analysis solution isn’t going to see it.

This in of itself presents a problem. What’s in that code that you’ve just pulled? What’s it doing? How do you know? One of the key parts of security is visibility: visibility into what’s being run in your network, visibility of what people are doing on your network. The same holds true for application security, you want to understand what all the code in your app is doing.

If your app is being developed by another company, you have no way of knowing that the source code they’re presenting is a true and accurate representation of what’s within the compiled app they’ve delivered.

And if you’re relying on an app which you didn’t develop, once again, you’re stuck.

So realistically within the App world, source code really isn’t going to cut it. You need to be able to scan the apps themselves. Being able to look directly at the object code allows you to analyze all the theoretical paths regardless of whether or not they’re from an SDK you’ve pulled in, some code your developer has written, or something that’s been written by an outsourced group. There’s no need to trust that the source code is the same as the artefact given and because no source code is needed, you can understand the risks of apps where you have no access to the source code.

Binary static analysis is great but it’s not everything.

So, binary static analysis is pretty great right? Yes it is but it’s not the whole story.

Firstly, it isn’t sound in the mathematical sense. What do I mean by that? Well, it can present false positives (states, which in theory are possible, but in practical terms aren’t) and false negatives (not finding an issue which can happen). The reason for this is because we’re not actually running the app–we’re making theoretical conclusions about the app from its object code.

Secondly, if any code is reflectively loaded (i.e., object code which is dynamically loaded), it will be missed. You can only scan object code which you can see. Again, this is because we’re not actually running the app. We can’t make conclusions about things we can not see.

The reasons these matter are because there has been a rather strange consequence of static analysis being used for the submission process: it’s made hackers more aware of it. Hackers and the more unethical of app developers have started to leverage techniques to circumvent traditional static analysis methods. They leverage the supply chain attacks we’ve talked about earlier which can be mitigated by the scanning of the object code rather than the source code. But they also leverage the dynamic loading of code.

There’s plenty of good and bad reasons for reflectively loading code. Generally, it’s not something you would need to do, but there are legitimate reasons to leverage it. You really have to be careful, not just from a security perspective but from a code quality perspective as well. If your code changes dynamically at run time, it’s hard to understand the state of your application at a given time. Also, if you’re pulling that code from the internet, you need to handle cases where it’s simply impossible to load. From a security perspective, it definitely represents a risk because you don’t know what code your app is actually running, and you now need to understand where that code is being loaded from. For instance, Ryan Johnson, a founder at Kryptowire and security researcher recently found a popular app was pulling a jar from: /storage/emulated/0/Android/data/

What’s the big deal right? Well, anything can write to that directory, so here is a convenient way of gaining access to all the permissions of that app and executing what you want hidden with that app.

Now what happens if one of those libraries you’re pulling in happens to load something reflectively? Things get scary because you’re putting a lot of trust in code which you don’t have a lot of visibility into.

Dynamic analysis vs. static analysis

So what’s the answer to this? Dynamic analysis, unlike static analysis, analyzes an app while it runs. The problem with typical dynamic analysis is that unlike static analysis, you only see what the app does. Because apps tend to require some user input, unless you’re providing that input for all the control paths, you’re not going to analyze those paths. This is a big problem with dynamic analysis in that there are techniques like randomly clicking on buttons etc, but there is no way of guaranteeing that leads to anything meaningful.

Again, the nice thing about static analysis was the exploring of all the control paths, not relying on things to be hit upon by things like unit tests, for example. But dynamic analysis is powerful as we’re actually testing code which is running, though we have no way of knowing that all the control paths are actually being tested. I remember many years ago being at Defcon where someone was presenting ways to bypass dynamic analysis of what was, at that point, the leading vendor of dynamic analysis. Their most successful bypass technique? Wait for the user to press enter. It was that trivial. Without a way of driving the application to do stuff, dynamic analysis offers very little in the way of insight.

We need a way of combining these 2 techniques together.

How Kryptowire paints the complete picture with static and dynamic analysis

When I say we need to combine these two techniques, I don’t mean simply do static analysis, and do dynamic analysis, like a lot of companies offer. Though this would indeed be better than doing just one of the analyses, it really doesn’t leverage the technology in the best way. What I’m talking about is the approach we take at Kryptowire. At Kryptowire, we take a unique approach to our analysis. Instead of just relying on static analysis and random clicking for dynamic analysis, we use our static analysis results to drive the dynamic analysis.

How do we do it? Well, we use static analysis to draw out the control flows, then we run the app and use our force path execution techniques to make sure that each of those control flows are actually taken. Reflectively loading code? No problem. Control path which only gets entered on the last week of the year? No problem, with our force path execution, we will force that path to be taken. Control Path which only happens with certain user input? Again we force it to take place. It doesn’t stop there, you need to log into a REST api to really drive testing? Simple, give us a test around and we’ll populate that into the app before doing our dynamic analysis.

This means we’re using our static analysis part of our pipeline to drive full dynamic analysis of the actual code. In fact, this is just a part of the pipeline we use at Kryptowire. It is not about each part being separate, it’s about one part of the analysis driving the next stage of the analysis. Making sure we get as close to full coverage as possible in a fully automated way.

As the Android and iOS security model becomes more tested and stressed, it’s important that the path you choose is tailored to that approach, rather than trying to adapt approaches taken for legacy web applications and shoe horning them into the Android and iOS world. The dog should be wagging the tail, not the tail wagging the dog.

There is a paradigm shift. The future of consumer computing is Android and iOS. This change brings new challenges and new ways of thinking about security. Kryptowire is at the forefront of tackling these challenges. We help you to understand and mitigate these issues both as a developer and as an enterprise as a whole. Check out the Kryptowire website to understand how we do that.

Blog

Being Static in a Dynamic World

What is static analysis?

Static analysis is an incredibly powerful tool for code quality and has had a major impact on the security of applications. But what is it? In the most simple of terms, it’s the analysis of the source code of an application. It studies each of the possible routes through an application from inputs to outputs and looks for issues. Issues can range from mallocs without frees, circular references, unchecked inputs being used to create SQL statements, into system calls or buffer overflows. It’s actually a lot more complicated and this wikipedia page has a good breakdown if you’re interested.

Within the Android and iOS world, static analysis is one of the checks that every app goes through when it’s submitted to the Play Store or the App Store and for good reason; it helps make sure that the code submitted is of reasonable standard.

Why do you need static analysis?

If you’re an app developer, why would you need static analysis? Google and Apple seem to have got you covered, right? Well, not really. While it is part of the submission process, it is part of their process, not yours–and it’s looking for the lowest hanging fruit rather than anything in depth. And do you really want your code quality gate to be at the right most part of your pipeline at submission? In a shift left world, being at the right most edge doesn’t sound particularly fun.

OK, so relying on the static analysis that Apple and Google have isn’t the best. I have thousands of unit tests, code coverage of over 90%, hundreds of integration tests, rigorous code reviews and many synthetic tests, so why on earth should I bother with Static Analysis? Well first, congratulations, and I mean that! Building out a robust testing infrastructure is a non-trivial task and definitely a worthwhile one. Still, even with this type of framework, can you guarantee you’re testing all possible control flows? All possible flows through your app? Probably not. Static code analysis can.

How do you go about static analysis?

Now that we understand why there’s a need for this type of analysis, let’s start thinking about how to go about it. First generation of static analysis and still a large amount of the current solutions out there rely on source code. While this might be fine for analysis of certain scenarios, it’s not a particularly effective approach with app development. Why? Because most of that app you’re creating is leveraging SDKs and those SDKs are object code. 40% to 90% of an iOS and Android App is typically composed of SDKs, they’re typically pulled in as object code, and even where there’s source code available, unless you’re compiling that source code as part of your build process, your static analysis solution isn’t going to see it.

This in of itself presents a problem. What’s in that code that you’ve just pulled? What’s it doing? How do you know? One of the key parts of security is visibility: visibility into what’s being run in your network, visibility of what people are doing on your network. The same holds true for application security, you want to understand what all the code in your app is doing.

If your app is being developed by another company, you have no way of knowing that the source code they’re presenting is a true and accurate representation of what’s within the compiled app they’ve delivered.

And if you’re relying on an app which you didn’t develop, once again, you’re stuck.

So realistically within the App world, source code really isn’t going to cut it. You need to be able to scan the apps themselves. Being able to look directly at the object code allows you to analyze all the theoretical paths regardless of whether or not they’re from an SDK you’ve pulled in, some code your developer has written, or something that’s been written by an outsourced group. There’s no need to trust that the source code is the same as the artefact given and because no source code is needed, you can understand the risks of apps where you have no access to the source code.

Binary static analysis is great but it’s not everything.

So, binary static analysis is pretty great right? Yes it is but it’s not the whole story.

Firstly, it isn’t sound in the mathematical sense. What do I mean by that? Well, it can present false positives (states, which in theory are possible, but in practical terms aren’t) and false negatives (not finding an issue which can happen). The reason for this is because we’re not actually running the app–we’re making theoretical conclusions about the app from its object code.

Secondly, if any code is reflectively loaded (i.e., object code which is dynamically loaded), it will be missed. You can only scan object code which you can see. Again, this is because we’re not actually running the app. We can’t make conclusions about things we can not see.

The reasons these matter are because there has been a rather strange consequence of static analysis being used for the submission process: it’s made hackers more aware of it. Hackers and the more unethical of app developers have started to leverage techniques to circumvent traditional static analysis methods. They leverage the supply chain attacks we’ve talked about earlier which can be mitigated by the scanning of the object code rather than the source code. But they also leverage the dynamic loading of code.

There’s plenty of good and bad reasons for reflectively loading code. Generally, it’s not something you would need to do, but there are legitimate reasons to leverage it. You really have to be careful, not just from a security perspective but from a code quality perspective as well. If your code changes dynamically at run time, it’s hard to understand the state of your application at a given time. Also, if you’re pulling that code from the internet, you need to handle cases where it’s simply impossible to load. From a security perspective, it definitely represents a risk because you don’t know what code your app is actually running, and you now need to understand where that code is being loaded from. For instance, Ryan Johnson, a founder at Kryptowire and security researcher recently found a popular app was pulling a jar from: /storage/emulated/0/Android/data/

What’s the big deal right? Well, anything can write to that directory, so here is a convenient way of gaining access to all the permissions of that app and executing what you want hidden with that app.

Now what happens if one of those libraries you’re pulling in happens to load something reflectively? Things get scary because you’re putting a lot of trust in code which you don’t have a lot of visibility into.

Dynamic analysis vs. static analysis

So what’s the answer to this? Dynamic analysis, unlike static analysis, analyzes an app while it runs. The problem with typical dynamic analysis is that unlike static analysis, you only see what the app does. Because apps tend to require some user input, unless you’re providing that input for all the control paths, you’re not going to analyze those paths. This is a big problem with dynamic analysis in that there are techniques like randomly clicking on buttons etc, but there is no way of guaranteeing that leads to anything meaningful.

Again, the nice thing about static analysis was the exploring of all the control paths, not relying on things to be hit upon by things like unit tests, for example. But dynamic analysis is powerful as we’re actually testing code which is running, though we have no way of knowing that all the control paths are actually being tested. I remember many years ago being at Defcon where someone was presenting ways to bypass dynamic analysis of what was, at that point, the leading vendor of dynamic analysis. Their most successful bypass technique? Wait for the user to press enter. It was that trivial. Without a way of driving the application to do stuff, dynamic analysis offers very little in the way of insight.

We need a way of combining these 2 techniques together.

How Kryptowire paints the complete picture with static and dynamic analysis

When I say we need to combine these two techniques, I don’t mean simply do static analysis, and do dynamic analysis, like a lot of companies offer. Though this would indeed be better than doing just one of the analyses, it really doesn’t leverage the technology in the best way. What I’m talking about is the approach we take at Kryptowire. At Kryptowire, we take a unique approach to our analysis. Instead of just relying on static analysis and random clicking for dynamic analysis, we use our static analysis results to drive the dynamic analysis.

How do we do it? Well, we use static analysis to draw out the control flows, then we run the app and use our force path execution techniques to make sure that each of those control flows are actually taken. Reflectively loading code? No problem. Control path which only gets entered on the last week of the year? No problem, with our force path execution, we will force that path to be taken. Control Path which only happens with certain user input? Again we force it to take place. It doesn’t stop there, you need to log into a REST api to really drive testing? Simple, give us a test around and we’ll populate that into the app before doing our dynamic analysis.

This means we’re using our static analysis part of our pipeline to drive full dynamic analysis of the actual code. In fact, this is just a part of the pipeline we use at Kryptowire. It is not about each part being separate, it’s about one part of the analysis driving the next stage of the analysis. Making sure we get as close to full coverage as possible in a fully automated way.

As the Android and iOS security model becomes more tested and stressed, it’s important that the path you choose is tailored to that approach, rather than trying to adapt approaches taken for legacy web applications and shoe horning them into the Android and iOS world. The dog should be wagging the tail, not the tail wagging the dog.

There is a paradigm shift. The future of consumer computing is Android and iOS. This change brings new challenges and new ways of thinking about security. Kryptowire is at the forefront of tackling these challenges. We help you to understand and mitigate these issues both as a developer and as an enterprise as a whole. Check out the Kryptowire website to understand how we do that.