Instructor: In this lesson,
we will learn about reverse engineering.
Reverse engineering breaks down software
or hardware components to understand their structure,
functionality, and potential vulnerabilities.
Reverse engineering concepts include byte code,
binary code, as well as disassembly and decompilation.
Byte code is a low level representation of code
that can be executed by virtual machines.
Binary refers to machine-level code
that the computer directly executes
and is made up of ones and zeros.
Disassembly is the process of converting binary code
into assembly language to analyze how software operates.
Decompilation goes a step further than disassembly
and attempts to translate executable code
into higher-level language for easier understanding.
Let's learn more about byte code, binary code,
as well as disassembly and decompilation.
First, we have byte code.
Byte code is a low-level representation of code
that is executed by a virtual machine.
It acts as an intermediate form
between high-level performing languages
and machine code, making it platform independent
and easier to execute across different systems.
Unlike assembly language, which is specific
to a processor architecture and directly corresponds
to machine instructions, byte code is designed
to be interpreted or compiled by a virtual machine.
A quick example of byte code
might look like what's on the screen.
In this example, the byte code represents
basic instructions like loading a constant
and storing it in a variable.
Byte code is generally more abstract
and portable compared to assembly language,
which would look more like what's coming onto the screen now
when conducting a similar operation.
So while both byte code and assembly language are low-level,
assembly is directly tied to the CPU architecture
and byte code remains architecture neutral,
relying on a virtual machine to execute it.
In forensic analysis, byte code is important
because it allows analysts to examine software or malware
without needing the original source code,
or worrying about platform-specific details.
For example, in the case of malware written in Java,
a forensic investigator can analyze the byte code
to identify malicious routines or patterns.
In forensic analysis, finding byte code for analysis
typically involves locating compiled byte code files
such as .class files for Java, .pyt files for Python,
or .dll files for .NET.
These files may be extracted from various sources
such as disc images or memory dumps during an investigation.
Additionally, a byte code may be stored
inside bundled archives like JAR files
for Java applications,
or ZIP files containing Python pyt files.
Often, once the byte code is located,
it can be decompiled to reveal its structure
and functionality, allowing investigators to analyze
the software or malware's behavior and intent.
Second, we have binary code.
Binary code consists of machine-level instructions
that a computer directly executes,
represented as ones and zeros.
Binary analysis plays an important role
in reverse engineering,
especially when the source code is unavailable.
This process allows investigators to understand
how software, firmware, or malware operates
by examining its raw binary form.
In forensic analysis, a binary code is essential
for evaluating executable files, firmware,
or even operating systems
to uncover potential vulnerabilities,
malicious behaviors, or hidden functionality.
Several tools assist with binary analysis,
including binwalk, hexdump, strace, and ldd.
Binwalk inspects firmware images to identify and extract
embedded components such as compressed archives,
file systems, and executable code,
making it important for reverse engineering firmware.
Next, hexdump is used to display binary files
in a human-readable hexadecimal format,
allowing analysts to examine the structure
and content of a file.
For example, during a forensic investigation
of an embedded device's firmware,
an analyst may use binwalk to extract
and inspect binary components,
potentially locating embedded malicious code.
Then, hexdump can help investigators manually inspect
the content of these binary files to identify patterns,
headers, or anomalies that suggest tampering
or malware insertion.
The next tool, strace, tracks system calls
made by a running binary during execution,
revealing how it interacts with the system
and whether it performs suspicious actions
like unauthorized file access.
And finally, ldd identifies the shared libraries
a binary relies on, helping analysts
understand the program's dependencies
and detect any unusual or malicious modifications
linked to libraries.
Third, we have disassembly.
Disassembly is the process of converting a binary code
into assembly language, which provides low-level
human-readable representation of machine instructions.
This allows investigators to understand
how software operates at a fundamental level,
without access to the original source code.
Disassembling malware or proprietary software
can reveal hidden features, vulnerabilities,
or malicious behavior.
In forensic analysis, disassembly provides insights
into how an application interacts with the system,
executes instructions, and performs
potentially harmful operations.
Popular tools for disassembly include IDA Pro, Ghidra,
and OllyDbg, or Olly Debug.
These tools help analysts break down binaries
into assembly language, revealing the sequence
of operations a program performs.
For example, in a forensic investigation,
if an unknown binary is discovered,
an analyst might use Ghidra or IDA Pro
to disassemble the file and investigate its system calls,
memory usage, and external communication
to uncover any suspicious activity,
such as attempts to steal sensitive information
or bypass security mechanisms.
In addition to pure disassembly tools,
debuggers like OllyDbg for Windows applications
and GDB, the GNU Project Debugger
for Linux and Unix systems,
also play a critical role in analyzing binaries.
These tools allow investigators to step through
the execution of a disassembled program in real time,
making it easier to identify specific behaviors,
vulnerabilities, or malicious actions.
A key feature in these debuggers
is the use of break points, which allow analysts
to pause the execution of a program
at specific points in the code.
By setting break points, investigators can closely examine
the state of the program, including memory, variables,
and register values at critical moments.
This helps pinpoint where suspicious behavior occurs
or where vulnerabilities may be exploited.
Fourth and last, we have decompilation.
Decompilation is the process of translating
executable binary or byte code
back into high-level programming language
such as C, Python or Java.
Unlike disassembly, which converts binary
to assembly language, decompilation aims to produce
higher-level human-readable code
that closely resembles the original source code.
This is especially useful in forensic analysis
when the goal is to understand the logic
and flow of a program in a way that is
easier to interpret than raw machine or assembly code.
Languages like Java, Python, and JavaScript
are among the most likely to be successfully decompiled
because they compile to intermediate byte code,
which retains significant structural information
from the original source.
For example, Java compiles to byte code
for the Java virtual machine, and tools like
Class File Reader can effectively reverse engineer
Java byte code back to Java source code.
Similarly, Python byte code produced in .pyt files
is often successfully decompiled
using tools like Uncompyle6.
Next, JavaScript, though not traditionally compiled,
can often be restored from obfuscated forms
using deobfuscators.
Finally, tools like the Java Executable Compiler
and Ghidra are frequently used for decompilation
and in forensic investigations
because they help reverse engineer suspicious applications,
uncover hidden malicious functions,
or reveal potential exploits.
Overall, decompilation simplifies the analysis process,
allowing investigators to identify patterns
or reconstruct the original intent
of the program more easily.
So remember, reverse engineering is all about
breaking down software or hardware components
to understand their structure, functionality,
and potential vulnerabilities,
it involves analyzing concepts like byte code,
binary code, disassembly, and decompilation.
Byte code is an intermediate representation of code
that virtual machines execute, while binary code
consists of machine-level instructions
executed directly by the computer.
Disassembly converts binary code into human-readable
assembly language, which helps investigators understand
how software operates at a fundamental level.
Finally, decompilation goes beyond disassembly
by translating executable code back into
high-level programming languages,
making it easier to understand and read.
These techniques are used in forensic analysis
for uncovering malicious behavior, hidden functions,
or vulnerabilities in software.