Which programming language produces binaries that are the most difficult to reverse engineer?
Have you ever wondered how someone might go about taking apart your favorite computer program to figure out how it works? The process is called reverse engineering, and it’s done all the time by software developers in order to learn from other programs or to find security vulnerabilities. In this blog post, we’ll discuss why some programming languages make reverse engineering more difficult than others. We’re going to take a look at why binaries that were originally written in assembly code are generally the most difficult to reverse engineer.
Any given high-level programming language will compile down to assembly code before becoming a binary. Because of this, the level of difficulty in reverse engineering a binary is going to vary depending on the original high-level programming language.
Reverse Engineering
Reverse engineering is the process of taking something apart in order to figure out how it works. In the context of software, this usually means taking a compiled binary and figuring out what high-level programming language it was written in, as well as what the program is supposed to do. This can be difficult for a number of reasons, but one of the biggest factors is the level of optimization that was applied to the code during compilation.
In order to reverse engineer a program, one must first understand how that program was created. This usually involves decompiling the program into its original source code so that it can be read and understood by humans.
Once the source code has been decompiled, a reverse engineer can begin to understand how the program works and look for ways to modify or improve it. However, decompiling a program is not always a trivial task. It can be made significantly more difficult if the program was originally written in a language that produces binaries that are difficult to reverse engineer.
Get 20% off Google Google Workspace (Google Meet) Standard Plan with the following codes: 96DRHDRA9J7GTN6 Get 20% off Google Workspace (Google Meet) Business Plan (AMERICAS): M9HNXHX3WC9H7YE (Email us for more codes)
Some Languages Are More Difficult to Reverse Engineer Than Others.
There are many factors that can make reversing a binary more difficult, but they all stem from the way that the compiled code is organized. For example, consider two different programs written in two different languages. Both programs do the same thing: print “Hello, world!” to the screen. One program is written in C++ and one is written in Java.
When these programs are compiled, the C++ compiler will produce a binary that is considerably smaller than the binary produced by the Java compiler. This is because C++ allows programmers to specify things like data types and memory layout explicitly, whereas Java relies on interpretation at runtime instead. As a result, C++ programs tend to be more efficient than Java programs when compiled into binaries.
However, this also means that C++ binaries are more difficult to reverse engineer than Java binaries. This is because all of the information about data types and memory layout is encoded in the binary itself instead of being stored separately in an interpreted programming language like Java. As a result, someone who wants to reverse engineer a C++ binary would need to spend more time understanding how the compiled code is organized before they could even begin to understand what it does.
Optimization
Optimization is a process where the compiler tries to make the generated code run as fast as possible, with the goal of making the program take up less memory. This is generally accomplished by reorganizing the code in such a way that makes it harder for a human to read. For example, consider this simple C++ program:
int main() { int x = 5; int y = 10; int z = x + y; return z; } This would compile down to assembly code that looks something like this:
main: ; PC=0x1001000 mov eax, 5 ; PC=0x1001005 mov ebx, 10 ; PC=0x100100a add eax, ebx ; PC=0x100100d ret ; PC=0x100100e As you can see, even this very simple program has been optimized to the point where it’s no longer immediately clear what it’s doing just by looking at it. If you were trying to reverse engineer this program, you would have a very difficult time understanding what it’s supposed to do just by looking at the assembly code. Of course, there are ways to reverse engineer programs even if they’ve been heavily optimized. However, all things being equal, it’s generally going to be more difficult to reverse engineer a binary that was originally written in assembly code than one that was written in a higher-level language such as Java or Python. This is because compilers for higher-level languages typically don’t apply as much optimization to the generated code since humans are going to be reading and working with it directly anyways. As a result, binaries that were originally written in assembly tend to be more difficult to reverse engineer than those written in other languages.
According to Tim Mensch, programming language producing binaries that are the most difficult to reverse engineer are probably anything that goes through a modern optimization backend like gcc or LLVM.
And note that gcc is now the GNU Compiler Collection, a backronym that they came up with after adding a number of frontend languages. In addition to C, there are frontends for C++, Objective-C, Objective-C++, Fortran, Ada, D, and Go, plus others that are less mature.
LLVM has even more options. The Wikipedia page lists ActionScript, Ada, C#, Common Lisp, PicoLisp, Crystal, CUDA, D, Delphi, Dylan, Forth, Fortran, Free Basic, Free Pascal, Graphical G, Halide, Haskell, Java bytecode, Julia, Kotlin, Lua, Objective-C, OpenCL, PostgreSQL’s SQL and PLpgSQL, Ruby, Rust, Scala, Swift, XC, Xojo and Zig.
I don’t even know what all of those languages are. In some cases they may include enough of a runtime to make it easier to reverse engineer the underlying code (I’m guessing the Lisp dialects and Haskell would, among others), but in general, once compiled to a target architecture with maximum optimization, all of the above would be more or less equally difficult to reverse engineer.
Languages that are more rare (like Zig) may have an advantage by virtue of doing things differently enough that existing decompilers would have trouble. But that’s only an incremental increase in difficulty.
There exist libraries that you can add to a binary to make it much more difficult to reverse engineer. Tools that prevent trivial disassembly or that make code fail if run in a debugger, for instance. If you really need to protect code that you have to distribute, then using one of those products might be appropriate.
But overall the only way to be sure that no one can reverse engineer your code (aside from nuking it from orbit, which has the negative side effect of eliminating your customer base) is to never distribute your code: Run anything proprietary on servers and only allow people with active accounts to use it.
Generally, though? 99.9% of code isn’t worth reverse engineering. If you’re not being paid by some large company doing groundbreaking research (and you’re not if you would ask this question) then no one will ever bother to reverse engineer your code. This is a really, really frequent “noob” question, though: Because it was so hard for a new developer to write an app, they fear someone will steal the code and use it in their own app. As if anyone would want to steal code written by a junior developer. 🙄
More to the point, stealing your app and distributing it illegally can generally be done without reverse engineering it at all; I guarantee that many apps on the Play Store are hacked and republished with different art without the thieves even slightly understanding how the app works. It’s only if you embed some kind of copy protection/DRM into your app that they’d even need to hack it, and if you’re not clever about how you add the DRM, hacking it won’t take much effort or any decompiling at all. If you can point a debugger at the code, you can simply walk through the assembly language and find where it does the DRM check—and disable it. I managed to figure out how to do this as a teen, on my own, pre-Internet (for research purposes, of course). I guarantee I’m not unique or even that skilled at it, but start to finish I disabled DRM in a couple hours at most.
So generally, don’t even bother worrying about how difficult something is to reverse engineer. No one cares to see your code, and you can’t stop them from hacking the app if you add DRM. So unless you can keep your unique code on a server and charge a subscription, count on the fact that if your app gets popular, it will be stolen. People will also share subscription accounts, so you need to worry about that as well when you design your server architecture.
There are a lot of myths and misconceptions out there about binary reversing.
Myth #1: Reversing a Binary is Impossible This is simply not true. Given enough time and effort, anyone can reverse engineer a binary. It may be difficult, but it’s certainly not impossible. The first step is to understand what the program is supposed to do. Once you have a basic understanding of the program’s functionality, you can start to reverse engineering the code. This process will help you understand how the program works and how to modify it to suit your needs.
Myth #2: You Need Special Tools to Reverse Engineer a Binary Again, this is not true. All you really need is a text editor and a disassembler. A disassembler will take the compiled code and turn it into assembly code, which is much easier to read and understand.Once you have the assembly code, you can start to reverse engineer the program. You may find it helpful to use a debugger during this process so that you can step through the code and see what each instruction does. However, a debugger is not strictly necessary; it just makes the process easier. If you don’t have access to a debugger, you can still reverse engineer the program by tracing through the code manually.
Myth #3: Only Certain Types of Programs Can Be Reversed Engineered This myth is half true. It’s certainly easier to reverse engineered closed-source programs than open-source programs because you don’t have access to the source code. However, with enough time and effort, you can reverse engineer any type of program. The key is to understand the program’s functionality and then start breaking down the code into smaller pieces that you can understand. Once you have a good understanding of how the program works, you can start to figure out ways to modify it to suit your needs.
In conclusion,
We can see that binaries compiled from assembly code are generally more difficult to reverse engineer than those from other high-level languages. This is due to the level of optimization that’s applied during compilation, which can make the generated code very difficult for humans to understand. However, with enough effort and expertise, it is still possible to reverse engineer any given binary.
So, which programming language produces binaries that are the most difficult to reverse engineer?
There is no definitive answer, as it depends on many factors including the specific features of the language and the way that those features are used by individual programmers. However, languages like C++ that allow for explicit control over data types and memory layout tend to produce binaries that are more difficult to reverse engineer than interpreted languages like Java.
What are the Greenest or Least Environmentally Friendly Programming Languages?
Technology has revolutionized the way we live, work, and play. It has also had a profound impact on the world of programming languages. In recent years, there has been a growing trend towards green, energy-efficient languages such as C and C++. C++ and Rust are two of the most popular languages in this category. Both are designed to be more efficient than traditional languages like Java and JavaScript. And both have been shown to be highly effective at reducing greenhouse gas emissions. So if you’re looking for a language that’s good for the environment, these two are definitely worth considering.
The study below runs 10 benchmark problems in 28 languages [1]. It measures the runtime, memory usage, and energy consumption of each language. The abstract of the paper is shown below.
“This paper presents a study of the runtime, memory usage and energy consumption of twenty seven well-known software languages. We monitor the performance of such languages using ten different programming problems, expressed in each of the languages. Our results show interesting findings, such as, slower/faster languages consuming less/more energy, and how memory usage influences energy consumption. We show how to use our results to provide software engineers support to decide which language to use when energy efficiency is a concern”. [2]
According to the “paper,” in this study, they monitored the performance of these languages using different programming problems for which they used different algorithms compiled by the “Computer Language Benchmarks Game” project, dedicated to implementing algorithms in different languages.
The team used Intel’s Running Average Power Limit (RAPL) tool to measure power consumption, which can provide very accurate power consumption estimates.
Get 20% off Google Google Workspace (Google Meet) Standard Plan with the following codes: 96DRHDRA9J7GTN6 Get 20% off Google Workspace (Google Meet) Business Plan (AMERICAS): M9HNXHX3WC9H7YE (Email us for more codes)
The research shows that several factors influence energy consumption, as expected. The speed at which they are executed in the energy consumption is usually decisive, but not always the one that runs the fastest is the one that consumes the least energy as other factors enter into the power consumption equation besides speed, as the memory usage.
Energy
From this table, it is worth noting that C, C++and Java are among the languages that consume the least energy. On the other hand, JavaScript consumes almost twice as much as Java and four times what C consumes. As an interpreted language, Python needs more time to execute and is, therefore, one of the least “green” languages, occupying the position of those that consume the most energy.
Time:
The results are similar to the energy expenditure; the faster a programming language is, the less energy it expends.
Memory
In terms of memory consumption, we see how Java has become one of the most memory-consuming languages along with JavaScript.
To conclude:
Most Environmentally Friendly Languages: C, Rust, and C++ Least Environmentally Friendly Languages: Ruby, Python, Perl
Although this study may seem curious and without much practical application, it may help design better and more efficient programming languages. Also, we can use this new parameter in our equation when choosing a programing language.
This parameter can no longer be ignored in the future or almost the present; besides, the fastest languages are generally also the most environmentally friendly.
If you’re interested in something that is both green and energy efficient, you might want to consider the Groeningen Programming Language (GPL). Developed by a team of researchers at the University of Groningen in the Netherlands, GPL is a relatively new language that is based on the C and C++ programming languages. Python and Rust are also used in its development. GPL is designed to be used for developing energy efficient applications. Its syntax is similar to other popular programming languages, so it should be relatively easy for experienced programmers to learn. And since it’s open source, you can download and use it for free. So why not give GPL a try? It just might be the perfect language for your next project.
Top 10 Caveats – Counter arguments:
#1 C++ will perform better than Python to solve some simple algorithmic problems. C++ is a fairly bare-bone language with a medium level of abstraction, while Python is a high-level languages that relies on many external components, some of which have actually been written in C++. And of course C++ will be efficient than C# to solve some basic problem. But let’s see what happens if you build a complete web application back-end in C++.
#2: This isn’t much useful. I can imagine that the fastest (performance-wise) programming languages are greenest, and vice versa. However, running time is not only the factor here. An engineer may spend 5 minutes writing a Python script that does the job pretty well, and spends hours on debugging C++ code that does the same thing. And the performance difference on the final code may not differ much!
#3: Has anyone actually taken a look at the winning C and Rust solutions? Most of them are hand-written assembly code masked as SSE intrinsic. That is the kind of code that only a handful of people are able to maintain, not to mention come up with. On the other hand, the Python solutions are pure Python code without a trace of accelerated (read: written in Fortran, C, C++, and/or Rust) libraries like NumPy used in all sane Python projects.
#4: I used C++ years ago and now use Python, for saving energy consumption, I turn off my laptop when I got off work, I don’t use extra monitors, my AC is always set to 28 Celsius degree, I plan to change my car to electrical one, and I use Python.
#5: I disagree. We should consider the energy saved by the products created in those languages. For example, a C# – based Microsoft Teams allows people to work remotely. How much CO2 do we save that way? 😉
Now, try to do the same in C.
#6 Also, some Python programs, such as anything using NumPy, spend a considerable fraction of their cycles outside the Python interpreter in a C or C++ library..
I would love to see a scatterplot of execution time vs. energy usage as well. Given that modern CPUs can turbo and then go to a low-power state, a modest increase of energy usage during execution can pay dividends in letting the processor go to sleep quicker.
An application that vectorized heavily may end up having very high peak power and moderately higher energy usage that’s repaid by going to sleep much sooner. In the cell phone application processor business, we called that “race to sleep.” By Joe Zbiciak
#7 By Tim Mensch : It’s almost complete garbage.
If you look at the TypeScript numbers, they are more than 5x worse than JavaScript.
This has to mean they were running the TypeScript compiler every time they ran their benchmark. That’s not how TypeScript works. TypeScript should be identical to JavaScript. It is JavaScript once it’s running, after all.
Given that glaring mistake, the rest of their numbers are suspect.
I suspect Python and Ruby really are pretty bad given better written benchmarks I’ve seen, but given their testing issues, not as bad as they imply. Python at least has a “compile” phase as well, so if they were running a benchmark repeatedly, they were measuring the startup energy usage along with the actual energy usage, which may have swamped the benchmark itself.
PHP similarly has a compile step, but PHP may actually run that compile step every time a script is run. So of all of the benchmarks, it might be the closest.
I do wonder if they also compiled the C and C++ code as part of the benchmarks as well. C++ should be as optimized or more so than C, and as such should use the same or less power, unless you’re counting the compile phase. And if they’re also measuring the compile phase, then they are being intentionally deceptive. Or stupid. But I’ll go with deceptive to be polite. (You usually compile a program in C or C++ once and then you can run it millions or billions of times—or more. The energy cost of compiling is miniscule compared to the run time cost of almost any program.)
I’ve read that 80% of all studies are garbage. This is one of those garbage studies.
This is nonsense as it runs low-level benchmarks that benchmark basic algorithms in high-level languages. You don’t do that for anything more than theoretical work.
Do a comparison of real-world tasks and you should find less of a spread.
Do a comparison of web-server work or something like that – I guess you may find a factor of maybe 5 or 10 – if it’s done right.
Don’t do low-level algorithms in a high-level language for anything more than teaching. If you need such an algorithm – the way to do it is to implement it in a library as a native module. And then it’s compiled to machine code and runs as fast as any other implementation.
#9 By Tim Mensch
It’s worse than nonsense. TypeScript complies directly to JavaScript, but gets a crazy worse rating somehow?!
For NumPy and machine learning applications, most of the calculations are going to be in C.
The world I’ve found myself in is server code, though. Servers that run 24/7/365.
And in that case, a server written in C or C++ will be able to saturate its network interface at a much lower continuous CPU load than a Python or Ruby server can. So in that respect, the latter languages’ performance issues really do make a difference in ongoing energy usage.
But as you point out, in mobile there could be an even greater difference due to the CPU being put to sleep or into a low power mode if it finishes its work more quickly.
Today I Learned (TIL) You learn something new every day; what did you learn today? Submit interesting and specific facts about something that you just found out here.
Reddit Science This community is a place to share and discuss new scientific research. Read about the latest advances in astronomy, biology, medicine, physics, social science, and more. Find and submit new publications and popular science coverage of current research.