>> Hello, welcome to cyber, my name is Sean Pierce.
I'm subject matter expert for
introduction to malware analysis.
Today we are going to be covering
the basics of static analysis.
We're going to go over Part 1 assembly.
What exactly is static analysis?
Well, we're going to read the raw assembly code
from an executable.
We use tools such as debuggers and disassemblers.
Now, when I say debugger,
you probably think, you're going to step
through each line of the source code.
That's not quite true.
If you have an IDE,
an integrated development environment,
debuggers are useful for finding bugs.
You step through each line of the source code say,
this is the if statement and this is the value
I'm comparing this variable against and etc.
Well, we don't usually have the source code,
in fact it's exceedingly rare that we do.
We step through each assembly instruction,
we're going to see some examples of that in a bit.
But several disassemblers do have debugging components
in them so you can run
the malware and if you ever do run the malware,
even with a debugger attached where you think
you can control each instruction,
I highly suggest you keep it in
a virtual machine or a VM,
like one we built in the earlier videos.
The characteristics of static analysis
is usually that it's very slow,
very detail oriented,
and with a lot of technical knowledge
required. I like it.
I don't think it's super hard once you get
the hang of it after
a few weeks of digging into something,
you get pretty comfortable with it pretty fast.
Especially if you're executing
some code over and over and over again,
you can see exactly what the instructions are doing.
But it does take time to sort
through rather large executables.
I wouldn't suggest starting with something like
Visual Studio or another large application,
like photoshop or something like that.
Because those are huge programs,
a megabyte worth of code is a lot of code.
Generally, when we're looking at code
statically and we are
looking at the individual instructions,
were trying to confirm our dynamic analysis.
We saw there it created a file in
this directory and it had this weird file name.
Is that name really hard-coded into the binary?
Will it use that name every single time?
Or did it choose that name based
>> on the date or the time,
>> or the version of the operating system?
Static analysis, we can really
understand the behavior of the malware and we can
understand what conditional behavior would
come about in a different version
of the operating system or
whether or not it had access to
the Internet or different things
about the family of
malware we're looking for
because that's very helpful too.
If we look at indicators like constants that we find,
or certain strings in the code you can just Google
for and you can see that someone else
has already done some analysis,
you can find out a lot of information.
Some strings in some malware are meant to be jokes.
They know that analysts are going to look at this
later and they try to make things harder,
like encrypting strings, they encrypt payloads.
If a piece of malware drops another file,
another executable and then executes that,
it's frequently, just encrypted in
the first dropping malware, the dropper.
It'd be interesting from a static analysis standpoint
to know when it would drop that.
I see that, it's going
to look at all the processes that are running.
If there's no processes named,
whatever debugger or have
the debugger keyword in the process title,
then I'll drop this other executable and kick that off.
We can also understand domain generation algorithms.
Some malware families out there
don't have hard coded domains or
IP addresses as command and control
servers to report back to but instead,
it gets us updates by generating
new malicious domains every single day
or every single second or every single minute.
It will use a time
or some other value like from the Internet,
like the weather or something like that.
It'll use that as a seed to
generate a domain name and then
check that domain name to see if
the malware author has put anything there.
Of course, a malware author usually signs off stuff,
so security researchers can't
just take over the botnet by
planting self-destruct configurations on
fake command and control servers.
We can also easily figure out, well,
not so easily sometimes,
but network traffic encryption.
Several families of malware will
encrypt their network traffic
to their command and control server.
Sometimes it's really easy to figure
out the encryption method they're using.
Usually it's a single byte XOR operation,
which is just one instruction
the CPU needs to run in
order to get its original traffic.
Sometimes if you look at string encryption,
you'll frequently see that it goes through
each byte and just XORs it against a value.
We can figure that stuff out statically without
running the executable and we can determine defenses.
A lot of malware out there has
anti-VM or anti-debugging defenses like I mentioned
earlier and if we dropped
an executable in our VM and
we double-clicked it and nothing happened,
or we can see in the log that it just started and
stopped and we don't really know why it's doing that,
we can throw it into a disassembler like IDA Pro,
and just look through
the code and see if anything jumps out at us
as being some kind of
anti-virtual machine technology
or anti-virtual machine code.
It's also important when
we really dig into a piece of malware,
what its capabilities are,
and what code wasn't
executed during dynamic analysis and really,
what is the risk and impact to your organization?
For example, I was given a piece of
malware and when I run it in a VM,
all it did was pop up and say,
you've been hacked by a hacker group name here,
and Explorer did a quick little refresh.
Within the first 30 seconds of static analysis,
I opened up an IDA and I
was looking at it and I was just like, oh,
it looks they just took a BAT file and
they ran a tool on it called BAT to EXE,
and made an EXE file.
I was able to recover the original BAT file,
which was just a few lines of code.
The first two lines ran a command to
disable the mouse and then run
another command to disable the keyboard,
and then it ran a command to take
the file and place it in the startup programs folder.
Then it would pop up,
you have been hacked,
then it would kill explorer.exe.
I know this my mouse and keyboard we're
working during this dynamic analysis
and I Googled around and I
found out those commands didn't work since Windows 95.
Furthermore, I guess,
in the older versions of the operating system,
when explorer.exe dies, it doesn't come back.
But on all modern operating systems,
they do or explorer.exe
responds as soon as it's no longer running.
It also occurred to me that
key.bat was probably the original file name.
It was trying to copy key.bat instead of key.exe,
which is what it's originally named.
I was able to determine pretty quickly that this
offered very little risk and very low impact.
It was very low impact to
anyone that was actually infected with it.
With static analysis,
after you do it a little while,
you can get a feel for how
sophisticated the programmer was.
I was able to look at that piece of malware and
determine that the actors were not very sophisticated.
There's obviously not very much testing.
They didn't realize that their are
persistence mechanism failed because
they renamed the file.
They didn't realize that
the keyboard and mouse we're still working after they
ran these commands and that
explorer.exe would just restart after it was killed.
Based on this and
other indicators from the region
this piece of malware came from I
was able to determine that
>> these attackers were not very
>> sophisticated and they were a lot of hype.
They talked a lot, but they didn't actually know a lot.
I was able to determine all this just really quickly
within 30 seconds of static analysis.
Dynamic analysis in this case
really did not help very much.
While I was looking at
this group that had made another piece of malware that
deleted all files on
the operating system or
that deleted all the files on the computer.
I looked at it again in static analysis
and saw that it was just a BAT to EXE file
running one command which was delete
everything recursively under the C drive forcefully.
I looked at another piece of
malware from the same region,
and it was also a wiper malware.
It used a driver,
a benign, well-known signed driver,
to get direct access to the hard drive
>> and then overwrite
>> the first several chunks of memory of
the hard-drive called the MBR
>> or the master boot record.
>> It was very faster,
and it was a much more sophisticated piece of malware.
I was able to attribute
one group's malware and
another group's malware to two different actors.
Earlier I was talking about we're going to
read the assembly of an executable.
What exactly is that?
Simple answer is it's human-readable machine code,
for a particular chip.
Each line of assembly usually corresponds
to a line of code that the CPU circuitry will execute.
Intel invented this 8086 chip several,
>> several years ago.
>> It was originally 8-bit and then 16-bit
>> and then 32-bit.
>> When I say 32-bit,
those are the size of the registers and thusly,
how much memory it could address.
32-bits when you address it via word or D word,
you could only maximally address
four gigs or gigabytes of memory.
The upper limit for
early 32-bit operating systems was four gigs of RAM.
We moved on to another Architecture,
64-bit architecture also called
AMD 64 because they're the ones who made the standard.
Then Intel made its own 64-bit
standard which was almost completely identical.
Most all 64-bit chips can run X86 code.
Like the chips have the circuitry
to run both sets of code.
If you ever look at X64 assembly,
we have in the lower left-hand corner,
it looks pretty similar to
the assembly on the right-hand side
which is X86 assembly.
We also have ARM architectures and MIPS architectures.
ARM is a lot more common than MIPS.
ARM is usually used in phones and tablets and
MIPS is in printers and MIPS in some tablets.
This is really just to show you
that there is lots of architectures out there,
lots of different chips out there.
The most common architecture found in
the world is X86 architecture.
We should really get to know
X86 assembly because that's
what most malware is written in.
Malware, like any other piece of software,
usually tries to keep with compatibility and
wants to infect as many machines as possible.
I was saying, down the left-hand side,
there is 64-bit code,
in the middle is ARM assembly,
and on the right is MIPS,
and on the far right and up half the page is
X86 and that's what we're going to dig into more here.
X86 uses a lot of different instructions.
I can't remember exactly how many there are
but it's not what we call a RISC architecture.
RISC is reduced instruction set
and X36 is known as a CISC,
is a complex instruction set.
That was because Intel wanted just to
have lots of instructions to do
>> lots of different things.
>> Because like I said, each line,
each instruction here is
physically executed on the circuitry.
If you could combine a whole bunch of
operations into one instruction,
your code theoretically will be faster.
But the 14 most common instructions
make up 90 percent of all code out there.
The first 14, the most common
14 are once I've listed here on the right,
and you're going to see these a lot
so I would suggest memorizing them.
When you're reading assembly,
there's two different ways to read X86 and that's
usually with the Intel syntax and the AT&T syntax.
With the Intel syntax,
it's generally right to left.
Here we see move EAX, five.
That means we're moving the value
five into the EAX register.
A register is the little bit of memory
>> that's in the CPU.
>> There's a couple of different registers.
We'll go over them in a minute.
But just know that when I
want to manipulate information in the CPU,
we do it with registers and they are super fast.
It's really slow to get memory or to
get something from RAM and it's
really slow to get something from the hard drive.
If you can do it with registers, you really should.
If you're worried about optimizing your code,
compilers do a great job of that.
We're going to see some of the different
compilers here in a minute.
Different compilers will produce different assembly.
We can take the same program and
use 10 different compilers on it
and it'll almost always be
different between each compiler.
If you do enough stack analysis,
you'll get to know the output of certain compilers.
You can just look at it and say, "Oh,
this was produced by Visual Studio," or, "Oh,
this was produced by Delphi," or, "Oh,
this was produced by whatever Visual Basic."
Or I named languages but you can usually tell that too.
You really need to know programming knowledge
to get into this like
loops and functions and
local variables and APIs,
application programming interfaces.
You can Google stuff as you go along
but if you're looking at
the assembly for a program and you see,
"Oh, there is this jump instruction and then there's
an increment instruction and then there's
another jump instruction and it does
some stuff and another jump instruction."
If you're a knowledgeable programmer,
you could spot that as like,
"Oh, that's a for-loop.
It's incrementing some counter value."
Then checking constant to see if it's over, under that.
Local variables are useful because we're
going to talk about the stack in the second video.
Application programming interfaces are
useful because you can usually tell a sophistication
of a actor or you can usually
tell the programming methodology.
If they like to create
their own sockets and read [NOISE] and
write information directly from them,
that's a different way to transfer
information over a network rather than
using the HTML or the
when I net libraries that Microsoft also provides.
I would also suggest that you would know a bit of math,
particularly binary, hexadecimal and decimal,
and how to convert between them.
We're going to do a little demonstration.
We're going to take some C code and compile it with
GCC and Cygwin which
is what I prefer and what
>> I suggested in earlier videos.
>> We're also going to do it in
the native Visual Studio compiler CL.
I'm going to start up a Cygwin terminal here.
The Cygwin shell here and do ls and there's a hello.c.
I'm going to display it on
the screen by saying cat hello.c.
We can see it is a simple program,
simple C program where it just includes the
library std io.h which is standard IO.
It uses the printf function
to print hello world to the screen.
We can say gcc hello.c.
It will compile it and then we can execute it.
The final output by default is a.exe.
We can execute it and there is hello world.
With gcc, you can also specify
-S function and compile it.
We will see that we now have the hello.s.
I'm going to run cat hello.s
and this is what we call a listing file.
This is the assembly,
the X86 assembly that the compiler
had to generate in order to fully
compile an EXE file.file hello.c,
these dots are basically
saying that these lines are just metadata.
They don't have any code equivalent.
That is output. They're actually sections of the file.
We can see that there is indeed some metadata,
these included by this compiler,
we can see it's using the AT&T syntax.
That's doing that pushl, novel,
andl, subl, call___main.
That's pretty interesting. Oh,
okay, there's no clear lines.
Just a reset there, just. Now we're
going to compile it with
the Visual Studio compiler
that Microsoft provides for
free which is very nice of them.
Under Visual Studio, you can
go to the Developer Command Prompt.
We're going to browse, we're going to change directory.
Let me increase the font here.
>> Cygwin/home/on. We see the a.exe,
the hello.c and the hello.s.
We're going to compile CL,
the Microsoft supplied C compiler,
we can do hello.c.
It created an object file and then created hello.exe.
We're going to execute hello.exe.
Hello World. Very simple.
Now my press up
and specify the /FA parameter,
and now the Microsoft C compiler
will have produced a hello.ASM file.
We can look at that,
the pad plus plus because it's nicely colored.
Go to Cygwin,
home, Sean,
hello.ASM and we'll also opened hello.s.
This is hello.ASM.
This compiler produce this assembly file,
this listing file and it was
nice enough to go line by line and
specify the assembly instructions
that were produced from that line of code.
Since we only had two lines of code,
it's not that big a deal,
but it could be pretty interesting.
I highly suggest that you experiment with this.
We can see that this is the Intel syntax,
XOR EAX, EAX.
That zeros out EAX,
no matter what value is in EAX, it is now zero.
It's just a very quick way of doing it,
and we can see some push or pop instructions
here and that deals with
the stack which we'll talk about next video.
We can see that it pushes an offset
aka it pushes an address
onto the stack and then it calls printf,
and we can see that
the address has to be somewhere in this file.
There it is. Hello World
and there's a 0a for the backslash n for the new line,
and then zero to mark the end
>> of the string and let see,
>> you can color this,
and the listing file produced by GCC,
we see that it has
some fewer instructions that it's in AT&T syntax.
I'm sure we could have put
out Intel syntax if we wanted to.
We can see that it's produced some different assembly.
If you're looking at both these files and
a dissembler with enough practice you can
see what was produced by what compiler.
Here we're going to use a dis-assembler called IDA Pro.
I download the demo for version 6.8.
I'm just going to get hit,
''Go'' here, and I'm going to pull
over my GCC executable,
and IDA is going to look at it
and try to load various debugging information.
Here it'll give me a graphical view
of the assembly that it's found.
This is where the main CRT startup function
is and or better known as main.
Then there's also a main function
here that will eventually
pass off control or be the actual main function.
This is a good bit of code that
the GCC compiler for Cygwin
has inserted into our executable.
If you want to reverse this some more, you could,
an easy way would be to look at
the imports and exports and we
can even go to strings because Hello World was a string.
Hello World, and we can see where that was accessed
by pressing ''X'' or just going to
this X reference over here,
and we can see our code was
basically in Intel Syntax is push,
EBP, move EPP,
SP, these are stack registers.
We'll talk about that in the next video.
It calls the main function here and
moves the pointer into
a certain location and calls the putS,
which is a better function than printf.
For many reasons, printf is very old,
but it will make the adjustments.
You can see up here that this blue area,
this is actually code,
and these areas either couldn't figure
out what it was or it's just data.
We can press the spacebar and actually
see that this code is
just a small part of what this file is,
that there's lots of other code there,
library code, boilerplate code,
data, just blank data.
Sometimes it's just references,
sometimes it's just zeros.
But the point is, the compiler took that bit of
code and created this executable.
With the same code,
Visual Studio created
>> a completely different executable.
>> Functionally they are the same.
But as we'll see, it looks completely different.
It's calling these functions,
and IDA didn't know what their names were,
it just gave it a name based
on the address it founded in memory.
We're going to use the same technique to
find the actual small bit of code that we wrote.
I'm going to go to View strings.
>> You see a lot of strings were included.
I'm going to find Hello World somewhere,
Control F, Hello, helloworld/n.
We found it here.
We can press X to see where it's referenced.
We see in this function,
so 401260 that there is a push EBP moves ESP.
EBP, like the other function
>> that we saw on the previous,
>> a.exe, and we can
see it's pushed and then this function is called.
If we scroll over this function and then scroll,
or if we hover over this function,
then scroll with our mouse wheel down,
it has another function and then that calls
two other functions that looks
like and provide some arguments.
The compiler-like Visual Studio will do this
mainly because of security and stability.
It will put in certain checks
between functions that it knows are vulnerable.
Print f is vulnerable to a certain type of exploit
called a print string
or a print format string vulnerability.
It will surround the Print f function
or Microsoft's implementation or
the print f function with
more code boiler plate code,
is sometimes what they call it.
This shouldn't be alarming, and like I said,
once you get used to analyzing a few pieces of code,
programs that you write yourself
or publicly available programs,
you'll see that compilers will
insert their own code or add their own stuff.
Like Visual Studio will add in
the call stack canaries to see if there's
a certain type of exploit called
a buffer overflow exploit,
which we will talk about when we talk about stacks.
Iar is the best assembler,
but it's not necessarily the best compiler.
>> That's okay.
>> But most reverse engineers
prefer the debugger called ory debug.
A debugger that a lot of
reverse engineers like to use is ory debug.
It's currently at 2.01 version wise,
and a lot of people still use
1.1 because a lot
of old plug-ins were written for
it for reverse engineering.
We're going to take our Hello.exe.
We can execute this and we see that it
pops and says, Hello world.
If we wanted to see what's up through
the program, we can just take it,
drop it into ory debug,
and we can see that we can step over each instruction.
Now, if ory debug scares you with
all this stuff, it's okay.
Just take it one step at a time,
one instruction at a time, if you will.
The shortcut for this step over instruction is F8,
so we can just single step through
the program as it's working.
We can see as the instructions are executed,
changes are being made to certain registers.
We'll get into this,
push instruction here in a bit,
but we can easily step
over the next call instruction here,
or we can step into it and we can
actually follow the program flow.
I'm just going to step over.
If we see this push instruction execute and
push onto the lower right-hand pane.
There is what we call the stack,
which we'll talk about in just a minute.
You step over and we can see that
something was pushed onto the stack.
Ory looks at it and knows it's
an argument to the next function,
which is a call here,
which we can step over again and pop the stack again,
which we'll talk about in just a minute.
There's a test, AL AL is testing to see if AL is 0,
and we'll talk about AL in a bit.
We can keep doing this until
>> we get to the point where it
>> calls the function that
actually prints Hello World to the screen.
We can see it's pushing two parameters,
it's calling another function.
Does a jump pushing two more parameters calls
another function into the Visual Studio
has added in a lot of code.
Somewhere here, probably this last function call
resulted in print f being called at some point,
and Hello World being displayed on the screen.
We can also do a similar thing with Visual Studio.
I'm going to end all you hear,
I'm going to grab this source code and copy it.
Now
that Visual Studio
has loaded I'm going to start a new project.
I'm going to choose empty project.
I'm just going to call it Project Hello.
I'm going to add a new file called hello.c,
I'll create it, I'll paste
in a Hello World code and save it.
Now I'm going to put a break point over here.
I'm going to say debug or Local Windows Debugger.
It's going to say, do you want to build this?
Yes, of course I do.
It will build the assembly.
It'll compile it,
it will produce an executable,
and begin to run it just like all we
did and stop it at a certain spot.
Now here's a really cool thing about Visual Studio.
You can right-click and say go to assembly.
Over here, it'll actually show
you for each line of code that you wrote,
the assembly that it created.
Just like the only debug program,
we can step over each instruction and then we can see
the resulting register is being changed.
If you want to look at all the registers onto Debug
under Windows, under registers.
Up here, we can see the EAX Register,
we can see EBX Register,
we can see the EIP Register being changed,
and we can do the same operation
where we step over each instruction,
and we can see exactly what it does
>> and when it does it.
>> We can see Hello World was printed.
This line of code was executed.
I highly encourage you to write
some source code and see the assembly that it produces,
because that's really the best way
to get to know compilers,
is really the best way to understand
what high level source code
produce what level or what assembly.
If you're feeling adventurous,
you can always change the architecture from
X86 to X64 and do the same thing.
Right-click. Or you can go over here,
see build this assembly.
You can see that they're
very similar type of instructions.
Instead of move EAX,
it will move at different value
>> into EAX or it'll produce
>> a different function call or
might do something slightly differently,
like instead of a push instruction,
it's using an LEA instruction
and doing something called a fascicle,
so it doesn't actually push or pop
>> anything on the stack.
>> It just places something in
the register because working
with registers are very fast.
But we'll get into calling conventions later.