Malware Analysis
Professional
String References & Basic
Patching
S e c t i o n 0 2 | M o d u l e 0 5
© Caendra Inc. 2020
All Rights Reserved
Table of Contents
MODULE 05 | STRING REFERENCES & BASIC PATCHING
5.1 Introduction
5.2 String References
5.3 A Few Words Before Starting
5.4 Let’s Start . . .
5.5 Conclusion
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.2
Getting Started
Tools:
• Olly Debugger v1.10
• HxD Hex Editor
• Windows Calculator
Target:
• RE_Lab_5.zip
www.ollydbg.de MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.3
5.1
Introduction
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.4
5.1 Introduction
The most important and necessary first step in reverse
engineering is to manage to locate the algorithm(s) that
we are looking for among all those thousands and
thousands of lines of assembly code that we see using a
debugger or a simple disassembler.
This can be achieved in various ways, depending on each
case. Some of them are more widely used in different
scenarios.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.5
5.1 Introduction
In this module we will be using the simplest methods for
doing so, and we will review the various advantages and
disadvantages of each.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.6
5.2
String References
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.7
5.2 String References
Using various references to specific strings of the
executable module under analysis, we can, in some cases,
locate the piece(s) of code that we need to analyze further.
By string reference, we mean an assembly instruction that
refers to a memory location where a string is stored.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.8
5.3
A Few Words
Before Starting
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.9
5.3 A Few Words Before Starting
During the first steps in the world of reversing we will be
dealing with behavioral observations regarding the
execution of an application and how it reacts (or not) to our
inputs.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.10
5.4
Let’s Start...
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.11
5.4.1 Run the Target Executable and Observe its
Functionality
Of course, in this case, the only thing that this program
does is to evaluate the input of the user and notify the user
with a message stating whether the code entered was right
or wrong.
In order to test this application, we will write something
random and then push the check button to see what
happens.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.12
5.4.1 Run the Target Executable and Observe its
Functionality
The message we get, “This code is invalid!!!” isn’t very
encouraging, but it really is helpful because we now have a
clue what to search for in the code of this application.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.13
5.4.1 Run the Target Executable and Observe its
Functionality
Why are we so interested in that? The answer is simple. In
this case, we have at least two possibilities regarding the
output of this application to the user. It will either accept
the code or not. We don’t know the right code or the output
in that case, but we certainly know the result of the wrong
input. This resultant output can lead us to the point where
the decision was made, and this is exactly what we’re
looking for.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.14
5.4.2 Load the Executable in the Olly Debugger
You should now be at the Entry Point (EP). The entry point
of an executable module is the address of the first
instruction to be executed inside the module itself.
Sometimes, we might refer to the EP of a specific function.
In that case we refer to the starting address of that function
where we commonly see the function prologue (Chapter 2,
2.4).
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.15
5.4.2 Load the Executable in the Olly Debugger
Different compilers generate different patterns of code in
the EP, even different compilers made for the same
programming language.
However, for now, it is enough to be familiar with the
concept of EP.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.16
5.4.2 Load the Executable in the Olly Debugger
Figure 5.1 Entry Point of RE Course Challenge #1
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.17
5.4.2 Load the Executable in the Olly Debugger
The EP of this application is located at address
0x004020D0, and in this case the first instruction is a short
unconditional jump instruction (JMP) which redirects the
EIP to the address 0x004020E2.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.18
5.4.2 Load the Executable in the Olly Debugger
NOTE: There is a specific type of function called a ‘naked’
function. Functions declared as such direct the compiler
not to generate a function prologue or epilogue, in order for
the programmer to write their own custom code at the
beginning and at the end of those functions.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.19
5.4.3 Search for String References
It is time to search for the clue we found before, which is
the message that let us know that the code we entered was
invalid.
In the CPU window, right click, and then → Search for → All
referenced text strings
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.20
5.4.3 Search for String References
In the figure on the next slide, we can clearly see the
message we saw when we entered the wrong code.
In this case we were able to find the reference we were
looking for very quickly because it is located near the top of
the list generated by Olly.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.21
5.4.3 Search for String References
Figure 5.2 String References – RE Course Challenge #1
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.22
5.4.3 Search for String References
In some cases, in order to save time instead of manually
searching, we can right click → Search for text.
Personally, when searching through this utility, I uncheck the
‘Case sensitive’ option and check ‘Entire scope’. We can then
search for more references to our required text by clicking
Ctrl + L.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.23
5.4.3 Search for String References
So, now we know that there is an instruction referencing that
string at address 0x402E9E, and if you double click on that
line you will be automatically transferred there.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.24
5.4.4 Reversing the Logic
The following screenshot shows what you should be looking at by
now.
Figure 5.3 Instruction referencing the string
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.25
5.4.4 Reversing the Logic
In the screenshot on the previous slide, we can see the two
possible outputs of this application. At address 0x00402E76
we can see the conditional jump instruction JNZ (jump if not
zero) where the decision is taken regarding the output.
A few instructions above at address 0x00402E6C we see a
CALL instruction and just before the unconditional jump we
see a TEST EAX, EAX instruction.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.26
5.4.4 Reversing the Logic
So what happens in reality is that the application is calling a
function, which returns a result to the EAX register.
Then, the application checks the value of EAX to see if it is
zero or not and if it is not, the conditional jump that follows
will redirect the execution to the bad message, otherwise the
execution will continue on with the good message.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.27
5.4.4 Reversing the Logic
Obviously, inside that function, the user-input data is
evaluated against correct data, but we will not dive in to
these details now since a basic overview of the application
logic is sufficient.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.28
5.4.5 Basic Memory Patching
Now that we understand the very basic logic of this
application, let’s try to ‘hack’ it, so that no matter what code
we enter, the application will always choose the execution
path of our choice.
In this case, it would be enough to simply patch only one
instruction, which is the conditional jump at address
0x00402E76.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.29
5.4.5 Basic Memory Patching
Here‘s the full instruction:
• 0x00402E76 75 1F JNZ 00402E97
Let’s break this down into pieces in order to explain what it does,
clearly.
• 0x00402E76 → VA of the first byte (0x75) of the instruction
• 0x75 → opcode (operation code) of the short JNZ jump
instruction.
• 0x1F → number of bytes to ‘skip’ or ‘jump’ by redirecting the EIP.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.30
5.4.5 Basic Memory Patching
In a few words, a short jump instruction (JZ, JNZ, JG, JL, etc.)
is a two-byte long instruction comprised of the opcode and
the number of bytes to redirect the EIP forward or backward
(-128 to +127 bytes).
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.31
5.4.5 Basic Memory Patching
So, in this case, the instruction starts at address 0x00402E76
with the opcode (0x75) and occupies one more byte space
for the number of bytes to jump (0x1F).
This means that this byte is located at 0x00402E76 + 1 =
0x00402E77.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.32
5.4.5 Basic Memory Patching
We can generally patch a conditional jump in three different
ways.
The first way is to substitute the whole instruction by using
NOPs (No Operation bytes). The opcode for this is 0x90.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.33
5.4.5 Basic Memory Patching
So in this case we would have:
• 0x00402E76 9090 NOP NOP
Select the instruction, then right click → Binary → Edit and
substitute both bytes with 0x90.
Run the application using F9 and enter a random code to see
the results, and then right click → Undo selection to restore
it back.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.34
5.4.5 Basic Memory Patching
Another way, which also requires modification of fewer bytes,
is to invert the logic of the jump.
In other words, turn the JNZ jump into a JZ (jump if zero)
jump. This will invert the logic in the sense that in this new
case, the application would accept every code as valid except
for the correct one.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.35
5.4.5 Basic Memory Patching
So, in this case we would have:
• 00402E76 74 1F JE 00402E97
Select the instruction, right click → Assemble and change
the JNZ to JZ and apply the modifications. As you see, only
the opcode has been changed.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.36
5.4.5 Basic Memory Patching
Enter again a code of your choice and evaluate the results.
Now restore the original code to test the final method.
Finally, instead of inverting the logic of the jump instruction,
we can modify it so that even if it does redirect the EIP, the
redirection will have no effect.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.37
5.4.5 Basic Memory Patching
We can achieve that by modifying the number that indicates
how many bytes to jump (0x1F in this case) to zero.
So, in this case we would have:
• 00402E76 75 00 JNZ 00402E78
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.38
5.4.5 Basic Memory Patching
As you can see, no matter which code we enter, the execution
will just continue with the next instruction which is exactly
what we want for this example.
Evaluate again the results by entering any code.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.39
5.4.6 Executable Patching Through Olly
During the previous section we saw different ways to patch a
conditional jump. However, all these were memory
modifications which are effective only in that specific running
instance of this application.
Often, we need to make these changes permanent which
implies that we need to write these modifications in the file
itself.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.40
5.4.6 Executable Patching Through Olly
In order to make these changes permanent, choose your
preferred method from above and once you apply it, select
the modified bytes → right click → Copy to executable →
Selection.
You can also choose ‘All modifications’ instead, unless you
have other modifications that you don’t want written to the
file.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.41
5.4.7 VA Offset Manual Calculation
As we mentioned in Chapter 4 (4.1), in order to permanently
modify the bytes we want, we have to know their offset inside
the physical file.
Olly Debugger does this calculation automatically (VA →
Offset), so you will not have to worry about this in the future,
but this doesn’t mean that you shouldn’t know how to do it in
case you ever need to.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.42
5.4.7 VA Offset Manual Calculation
In order to manually patch the bytes we are interested in
through a hex editor, we need first to know their offsets - their
position from the beginning of the file.
As we saw in Chapter 4 (4.3), the alignment of the executable
as mapped in memory is different from the one in the
physical file on the disk.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.43
5.4.7 VA Offset Manual Calculation
However, inside the header of the executable we can find all
the necessary information we need to manually calculate the
offset of a specific byte from its VA in memory.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.44
5.4.7 VA Offset Manual Calculation
1. We need to know which section the byte we are interested
in is. If you press Alt+M in Olly you will see how the
executable is mapped in memory along with all loaded
modules.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.45
5.4.7 VA Offset Manual Calculation
For this example, I am going to pick the third option from
above, so I want patch the byte located at VA 0x00402E77.
Let’s take a look at the memory map of the target executable.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.46
5.4.7 VA Offset Manual Calculation
Figure 5.4 Memory Map of RE Course Challenge #1
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.47
5.4.7 VA Offset Manual Calculation
As we can see the first section (.text), which contains the
executable code of this application, starts from VA
0x00401000 and has a size of 0x0023A000.
So, we know that our byte is within that range, and it belongs
to the first section.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.48
5.4.7 VA Offset Manual Calculation
2. We also should notice the Image Base, which is
0x00400000 - the default Image Base for an executable file in
Windows. Of course, this can be modified, but we won’t.
We need some more information to calculate the offset of
that byte, which we will retrieve from the header of this file.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.49
5.4.7 VA Offset Manual Calculation
3. Choose the first line (0x00400000) and Right click →
Dump in CPU.
Then, in the data window, right click → Special → PE header.
This will decode the header structures into a human-readable
format.
Scroll down until you see the following:
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.50
5.4.7 VA Offset Manual Calculation
Figure 5.5 .text Section details of RE Course Challenge #1
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.51
5.4.7 VA Offset Manual Calculation
In the figure on the previous slide, we see the
IMAGE_SECTION_HEADER structure (Chapter 4) of the
section we are interested in. As you can see, the first member
of this structure stores the section name.
Of course, there might be cases in which more than one
section has the same name, but this is not a problem. Apart
from the fact that their order is going to be the same as in the
memory map; we can always identify them by the value of
their RVAs.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.52
5.4.7 VA Offset Manual Calculation
Let’s explain the few first lines once more.
• VirtualSize: The size of the section in memory.
• VirtualAddress: The RVA of the section in memory, not the
VA.
• SizeofRawData: Size of the section in the file.
• PointerToRawData: Starting offset of the section in the
file.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.53
5.4.7 VA Offset Manual Calculation
4. Now, we have all the necessary information we need to find the
offset of the byte using the following formula:
Byte_Offset = Byte_VA - (Image_Base + Section_RVA) +
PointerToRawData
Which, in this case, would be:
• Byte_Offset = 0x00402E77 - (0x400000 + 0x1000) + 0x600 =
0x2477
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.54
5.4.8 Manual Byte Patching
We can now load our target into the hex editor and press Ctrl+G to
enter the hex value of the offset of the byte we just calculated from
the beginning of the file.
You only need to: modify the 0x1F byte with 0x00, save the new
executable with another name, and evaluate the changes. This is
shown on the next slide.
You should, at this point, try to apply the other two fixes manually
to gain some practice.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.55
5.4.8 Manual Byte Patching
Figure 5.6 Byte Patched in RE Course Challenge #1
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.56
5.5
Conclusion
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.57
5.5 Conclusion
During this module we covered a lot of information on the
simplest method of locating an algorithm we are interested
in.
However, as we know, the simplest method is not always
the appropriate one to use. Indeed, this method might be
fast, but we cannot always rely on it. For example, what
would happen if those strings were encrypted? Most likely,
this method would have become useless.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.58
5.5 Conclusion
On the other hand, this doesn’t mean that this isn’t a
method that we can still use in many cases.
In the next chapter, we will be discussing a more reliable
method used in order to reach the parts of the code that we
want to examine and we’ll also evaluate some information
which can be retrieved from the stack.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.59
VIDEO
Check out the video on
String References and Basic
Patching!
To ACCESS your video, go
to the course in your
members area and click the
resources drop-down in the
appropriate module line.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.60
LAB
Put what you’ve learned to
practice with the
RE_Lab_5.zip!
To ACCESS your lab, go to
the course in your members
area and click the resources
drop-down in the
appropriate module line,
your file will then download.
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.61
References
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.62
References
Here’s a list of all references linked or used in this course.
Olly Debugger v1.10
www.ollydbg.de
HxD Hex Editor
www.mh-nexus.de/en/hxd/
Windows Calculator
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.63
Videos & Labs
Here’s a list of all videos and labs in this module. To ACCESS, go to the
course in your members area and click the resources drop-down in the
appropriate module line.
String References and Basic Patching
RE_Lab_5.zip
MAPv1: Section 02, Module 05 - Caendra Inc. © 2020 | p.64