[go: up one dir, main page]

0% found this document useful (0 votes)
98 views45 pages

Malware Analysis Professional: Debugging Multi-Thread Applications

Uploaded by

Saw Gyi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
98 views45 pages

Malware Analysis Professional: Debugging Multi-Thread Applications

Uploaded by

Saw Gyi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 45

Malware Analysis

Professional

Debugging Multi-Thread
Applications
S e c t i o n 0 2 | M o d u l e 1 5
© Caendra Inc. 2020
All Rights Reserved
Table of Contents
MODULE 15 | DEBUGGING MULTI-THREAD APPLICATIONS

15.1 Introduction 15.4 Threads Synchronization

15.2 Multi-Threading in 15.5 Threads Manipulation


Practice
15.6 Debugging Multi-Thread
15.3 Creating a New Applications
Thread
15.7 Conclusion

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.2


Getting Started

Tools:
• Olly Debugger v1.10

Target:
• RE_Lab_15.zip

www.ollydbg.de MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.3


15.1

Introduction

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.4


15.1 Introduction

In this module we will be discussing about the debugging


and the analysis of multi-thread applications, or in other
words of applications that are able to execute various
blocks of code via different threads.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.5


15.1 Introduction

Reverse Engineering multi-thread applications can


sometimes be quite frustrating, especially for beginners.

However, by understanding the concepts behind the


creation of multiple threads on runtime we can successfully
monitor and keep control of all the threads in order to
ensure that nothing will pass under our radar.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.6


15.1 Introduction

Furthermore, during the demo video we will also play


around with a multi-thread application and will not just
show how to successfully debug the individual threads and
recognize which thread we are currently debugging, but
also how to turn the application into a single-thread by
performing code modifications.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.7


15.2

Multi-Threading in
Practice

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.8


15.2 Multi-Threading in Practice

Modern applications, including those malicious (malware),


are very often multi-threaded. This means that they are able
to assign different blocks of code to be executed via a
different thread.

Multi-threading can be very powerful if used appropriately


and can significantly improve the performance of an
application.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.9
15.2 Multi-Threading in Practice

In order to make this clear, think of the following example.


Let's say that we have an application that the only think that
it does is to receive two integer inputs from the user and
perform different mathematical operations between them,
such as addition, subtraction, division, and multiplication.

Let's assume that this application is well designed and


structured so that there is a dedicated function for each
one of those operations that performs a specific
mathematical operation and then prints the result.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.10
15.2 Multi-Threading in Practice

In a single-thread application these functions will be called


one by one so one function needs to end before the next
one is called.

In a multi-threaded application, we can assign a different


thread for each one of those functions so that they can be
executed simultaneously. This makes more sense with
modern Operating Systems and multi-core CPUs.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.11
15.2 Multi-Threading in Practice

Of course, multi-threaded programming has its own


drawbacks in terms of design difficulty, since in more
realistic scenarios, multiple threads require synchronization
among them in order to combine their outputs to the final
result, or just because one of the threads needs to wait for
others to finish before proceeding with its execution which
might depend on the output of other active threads.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.12


15.2 Multi-Threading in Practice

A few words before starting...


Before proceeding with this chapter, please make sure that
you have well understood the theory of the previous
chapters, and especially Chapter 2 where we discuss about
processes, threads, the stack etc...

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.13


15.3

Creating a New
Thread

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.14


15.3 Creating a New Thread

The Windows APIs mainly used to create a new thread are


the following:
• CreateThread
• CreateRemoteThread
• CreateRemoteThreadEx

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.15


15.3 Creating a New Thread

The CreateThread API creates a new thread inside the


virtual address space of the calling process, while the other
two APIs are used in order to inject a new thread in the
virtual address space of another process.

They all return a handle to the newly created thread, unless


the function fails for any reason that might be.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.16


15.3 Creating a New Thread

There are some other functions that we can use in an


executable that makes use of the C run-time library (CRT),
or in other words the MSVCRT library:
• _beginthread
• _beginthreadex

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.17


15.3 Creating a New Thread

These two functions are wrappers around the CreateThread


API, which means that this API will be called in the end in
order for the OS to start the new thread.

However, apart from the input parameters, there are also


some other differences between these functions which
make more sense regarding thread synchronization as we
will be discussing in the next section of this chapter.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.18
15.4

Threads
Synchronization

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.19


15.4 Threads Synchronization

In multi-threaded applications, it is very important to synchronize


the threads among them, if that of course is necessary. Unless
you want to have a thread constantly running, and/or completely
independent of the other running threads, then you can't avoid
thread synchronization.

A simple example of a new thread created that does not depend


on (or care of) any other thread, would be an algorithm
constantly running in its own thread that the only thing is doing is
to check if a specific process with a specific name is running.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.20
15.4 Threads Synchronization

There are various Windows APIs that can be involved with


the synchronization process, but there are two that are the
most commonly used in order to synchronize the execution
of more than one threads, or the completion of an
operation, such as killing another process.
• WaitForSingleObject
• WaitForMultipleObjects

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.21


15.4 Threads Synchronization

These APIs will put the calling thread in a 'wait' state until
the operation involved with the object(s) specified by the
handle, or the array of handles, such as the termination of
one or more running threads, is completed.

In order to use these APIs, the hande(s) specified must


have the SYNCHRONIZE access right.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.22


15.4 Threads Synchronization

We can also use the WaitForSingleObject, for example, to


wait for the termination of a process that our application is
trying to kill.

Going back to the APIs mentioned earlier regarding the


creation of threads, the most important difference among
them is that the _beginthread API should not be used when
synchronization among the threads is required and for this
reason, we will not take in consideration this API for the
rest of this chapter.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.23
15.4 Threads Synchronization

The main reason for this, is that the handle to the new
thread created by this API is not guaranteed to be valid. If
for example the new thread created with that API
terminates very quickly, then the handle returned to the
caller might be invalid or pointing to another thread,
because the handle associated with the new thread is
automatically closed upon its termination.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.24


15.4 Threads Synchronization

However, when we use the other APIs mentioned to create


a new thread, then the handle returned is guaranteed to be
valid since it has to be closed by the caller of those APIs.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.25


15.5

Threads
Manipulation

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.26


15.5 Threads Manipulation

When creating a new thread we can choose its creation state


which can be either in suspended mode (CREATE_SUSPENDED)
or let the thread to run immediately after creation.

In the first scenario the new thread will stay in suspended mode
until the caller uses the ResumeThread API. It is also possible to
suspend or kill a running thread by using the SuspendThread and
TerminateThread (or _endthreadex if the new thread was created
using the _beginthreadex function) APIs respectively.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.27
15.5 Threads Manipulation

In more advanced scenarios, a thread might want to have


access to more detailed information of another thread,
such as its entire context, which represents the CPU state
for that thread, such as the values of specific CPU
registers.

This can be achieved through the GetThreadContext API.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.28


15.5 Threads Manipulation

On the other hand, a thread might want to perform changes


in the context of another thread. In that case it will make
use of the SetThreadContext API.

In order to achieve both of these operations the handle to


that thread must have THREAD_GET_CONTEXT and/or
THREAD_SET_CONTEXT access rights respectively.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.29


15.5 Threads Manipulation

Usually, we need both access rights, since we first read the


context info that we need to a CONTEXT structure (Chapter
3, 3.4) using the GetThreadContext API, and then after
modifying the desired values in that structure, we use it to
apply the modifications to the context of the thread through
the SetThreadContext API.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.30


15.5 Threads Manipulation

However, there are some other issues that we need to take


in consideration when reading/writing to the context of
another thread, and that is that the context information
retrieved from a running thread will not be reliable since it
changes all the time during the execution of that thread.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.31


15.5 Threads Manipulation

For this reason, we first need to suspend the targeting


thread in order to ensure that the context information we
are reading is the actual one, and then after modifying and
applying the modifications to the context, we can resume
its execution.

For this reason the handle to the targeting thread must also
have the THREAD_SUSPEND_RESUME access right.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.32
15.5 Threads Manipulation

NOTE: In more advanced scenarios, such as the creation of


a new thread that runs in the address space of a new
process, we need to make use of more Windows APIs since
our process needs to have access to the target process to
allocate some extra memory in its address space and also
be able to inject code there that will run from the new
thread.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.33


15.6

Debugging Multi-
Thread Applications

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.34


15.6 Debugging Multi-Thread Applications

This might sound quite scary to people new in the area of


software Reverse Engineering but in reality, it's not that bad.

The most important thing, is to be aware of the APIs that


can be used in the OS you are working on for the creation of
a new thread. Once you have that information, you can
monitor the usage of those APIs so that you will know when
a new thread is going to be created before it does, which
brings you always one step ahead of it.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.35
15.6 Debugging Multi-Thread Applications

Furthermore, depending on each case the debugging


process might be affected by the scheduling of the
different threads by the OS due to the synchronization
requirements, but also this is not always a problem, since
many times extra threads are not really needed to correctly
run an application, but there are only there for performance
reasons, which means that we can also turn a multi-thread
application to a single-thread.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.36


15.6 Debugging Multi-Thread Applications

In the practical challenge that comes along with this


module, we will have the chance to deal with issues arising
when debugging a multi-thread application in order to
successfully reverse engineer it and reveal its secrets.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.37


15.7

Conclusion

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.38


15.7 Conclusion

Debugging multi-thread applications might require some


extra work but it is not really a rocket science. It only needs
a specific strategy and some good knowledge of the APIs
used by the OS we are working on.

So, when you see a process having more than one active
threads, you know which APIs might have used and all you
need to do is to monitor for those and place some
breakpoints at the entry points of the functions scheduled
to run via a new thread.
MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.39
15.7 Conclusion

In some cases, as shown in the video you can also turn a


multi-thread application, a malware for example, into a
single-thread one and avoid in that way any issues that
might arise by debugging a multi-thread application.

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.40


VIDEO

Check out the video on


Debugging Multi-Thread
Applications!

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 15 - Caendra Inc. © 2020 | p.41


LAB

Put what you’ve learned to


practice with the
RE_Lab_15.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 15 - Caendra Inc. © 2020 | p.42


References

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.43


References
Here’s a list of all references linked or used in this course.
Olly Debugger v1.10
http://www.ollydbg.de/

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.44


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.

Debugging Multi-Thread Applications

RE_Lab_15.zip

MAPv1: Section 02, Module 15 - Caendra Inc. © 2020 | p.45

You might also like