>> Welcome to Cybrary. Hi, my name is Sean Pierce.
I'm the subject matter expert
from Introduction to Malware Analysis.
Today, we're going to be talking about Part 2,
>> the Assembly Execution.
>> How do we go from raw assembly to a exe file?
Well, the compiler created
the raw executable code
and then included it in this container,
and this container is called a PE file.
Windows usually uses these PE files
to know what section of the code to begin executing,
what libraries it needs,
and what version of what compiler made it,
and all this other metadata about the executable code.
If you want to go explore that,
I highly suggest it
because there's a wealth
of information that we can use in there,
such as timestamps, like the compiler
usually adds in when this file was made.
Usually, it says what
its target platform and architecture for are,
what function CALLs it is going to call,
and other information like that.
There are several PE file format parsers;
PE Explorers, COFF Explorer,
PEiD, PE Studio,
010 Hexeditor is really good if you use
a PE file binary template.
Of course, you can make your own.
It's not super hard to do,
and there's a lot of work already done for that.
If you look at the Malware Analysis Cookbook,
they have a lot of scripts to help you with that
and you get to know the file format very well.
What uses the PE file format?
Simply .exe files are the most common.
Dll files are the exact same format with just a few
flags changed and a few more function exports are made.
The dll main being the only one
that a dll file needs to export in order
for it to be used and loaded up by the Windows loader
for execution, .src files are screensaver files,
but they execute code the exact same way.
As a demonstration,
we'll open up our Cygwin terminal here,
and when we were talking last,
we made several files like a .exe prints Hello World.
I'll just cut the Hello World file so you can see it.
Very simple program.
We can change a .exe to any one of these things,
such as a .fon do another list.
We see that there is a .fon,
we're going to execute that.
It prints Hello World. It's the same file format.
Sometimes malware will use these other extensions,
but it gets to be highly suspicious.
Most I've seen is src.
So we can do like this a .src
>> and we can execute a .src,
>> and it still executes it just like it
would any other exe file.
It's good to be aware of this.
We're talking about assembly
and we're talking about actually executing it.
I said I mentioned the flags register later,
and this is why it's
so important is because it keeps
state of the instructions.
If you look over on the far right here,
we have some x86 assembly.
The first line is move 1 into eax.
The next line, a compare instruction is move
2 or compare eax to the number 2.
The instruction below that is jz,
jump if 0, is what it stands for.
Basically, if the above operation
was resulting in zero,
then it would jump.
The compare instruction does
the same thing as a subtract instruction,
except it doesn't store
>> the result back to the register.
>> All it does is change the flag's register.
When compare eax,
2 was executed, it would do a subtraction operation,
so it subtracted 2 from eax.
This would result in negative 1,
but it would not result in 0.
If you see in the middle picture,
the zero flag and right above it,
the sign flag, the sign flag would be flipped,
so it would be a one in
the sign flag and the zero flag would be zero.
False, zero. True, one.
The zero flag would be zero,
sign flag would be one,
and so since zero was not flagged,
this jump will not work.
It will not jump to the label is 2,
which is on line 6.
It will just simply fall through to the label is not.
Labels don't actually do anything.
There's no assembly equivalent.
They're just placeholders.
What will happen is,
line 5 would be executed or
two will be moved into the eax register,
and then line 6 will be executed.
But since label doesn't
actually equate to any assembly code,
line 7 will be executed.
Zero will be moved into eax.
With these conditional jumps,
compilers will turn If statements and
loops and other control flow
mechanisms like spaghetti code
or switch statements, or
>> whatever into these instructions.
>> There are other flags that you should be aware of,
but those are the biggest;
is the sign flag and the zero flag.
Overflow and underflow flags will generally tell you
if you try to multiply or do something
else and you lost some information,
the overflow and underflow flag will be flipped,
and sometimes code is good enough to check for that.
The carry flag to see if there is
a operation that you added
some bytes to some register
and the results have a carry bit.
But like I said the most important ones
are zero and sign.
I talked about the PUSH and the POP instructions,
and the ESP, and the EBP registers,
and I said that it had to do with the stack.
Here we're going to look at how
x86 uses this data structure,
which is almost always at the top of memory,
where the operating system
is down at the bottom of memory,
and the heap where malloc and calloc get
new memory is in the middle.
Stack is slowly growing down.
It starts at a really high memory address,
and every time you do a PUSH,
it'll decrease the ESP
which points to the top of the stack,
and the EBP is always above it.
The base pointer is
always putting at the bottom of the stack,
which is at the highest memory address.
This might be hard to wrap your head around,
and a lot of people get confused by this.
If you care to just draw it
out on a piece of paper every once in a while,
that really helps. It helps me at least.
The PUSH instruction decrements the stack pointer.
It's like you're adding more memory to the stack.
It's like you have a stack of plates like an
all you can eat buffet or something and
you put them somewhere,
and every time you put a plate on top,
the whole stack moves down a little bit.
If you want to grab a plate,
you have to pop off the one on top.
If you POP something,
then you will take the data from that stack and
the ESP value will increment by typically four bytes.
There are PUSH and POP instructions that can do
16 bits which is two bytes.
But the most common
is PUSH four bytes and POP four bytes.
The CALL instruction will also affect the stack because
each stack frame between the ESP and EBP pointer,
each stack frame is the local scope for that function.
All local variables will be between the ESP and the EBP.
If this sounds confusing, don't worry,
you can look at some assembly of what the functions are
doing and you will see how
the stack is being manipulated for each function CALL.
When you CALL something,
you PUSH the EIP value onto the stack.
Wherever your current place in memory
is or the next instruction that is to be executed,
is PUSHed onto the stack.
Then you're going to JMP to
a location in memory, another location.
Then when you CALL the RET instruction
or the return instruction,
the EIP is going to be repopulated with
that address that the CALL instruction
had PUSHed onto the stack,
and it is going to
resume execution in that place that you called from.
If it sounds confusing, don't worry.
You're going to see some assembly and
it's going to make a bit more sense.
As I said, the stack grows downwards.
When you look at assembly and there's local variables,
and we'll see an example in a little bit,
you'll see them usually addressed from EBP.
Like be EBP plus a certain value,
or more appropriately, EBP minus a certain value.
If I want to access
the last parameter of a function CALL,
it will be EBP minus 4.
>> When I do a print F and pass it a single parameter
of Hello World or a pointer to the string Hello World,
the function will reference
that parameter by EBP minus 4.
That's how it accesses that pointer to that string.
I'm going to let that sink in for just a minute.
Just a little miscellaneous information.
There is something called a NOP instruction,
that stands for no operation.
It's an alias to the exchange EAX EAX instruction.
It moves EAX into EAX.
It results in nothing.
The NOP instruction is very useful if you want
to manipulate malware so that you can say,
I see it's doing a function
called check to see if there's
a debugger and dies if there's a debugger.
It NOPs out, you
can just put in NOP instructions in there.
That will result in
the CPU just completely
doing nothing for those instructions.
I can show you example of NOPing out some instructions.
I showed you the flags register.
Bit mask is good to know because it's
doing basically a logical AND to
isolate a piece of memory that it wants to.
Here are some examples where we want to get to
a certain bit or a certain byte
>> to see what the value is.
>> We do a Boolean logical AND.
If you are curious about how this works,
if you look at it enough certainly
you'll eventually come across it.
But it's not that big a deal.
You should just be aware of it.
Endianness, as I pointed out earlier,
is when bytes are swapped around when in storage.
When they're in registers, they look normal,
where the most significant value
is on the left-hand side.
When we typically read from
>> left to right in our culture,
>> and we're going to cover that here in a bit.
You should also know the nomenclature
surrounding data types,
such as WORD, DWORD, and QWORD.
In academia, WORD means
the unit of memory in architecture terms,
the base unit of memory in architecture terms.
If I'm talking about a 32-bit computer,
a WORD is generally 32-bits.
But when Intel and
Microsoft were making their programming languages,
they had to keep with compatibility
and the original WORD for
the original 8086 chip was 16-bits.
They pretty much made WORD synonymous with 16 bits.
You'll often see in Microsoft APIs
and websites in code, the term DWORD,
which is double word,
which is pretty much synonymous
with 32 bits or four bytes.
QWORD is quad words,
so it's double that,
so 64 bits aka eight bytes.
This is the difference between practical,
industry-standard, and academia.
Just be aware that when you see WORD or
DWORD or QWORD, it means 16,
32, and 64 bits
almost always unless you're reading a textbook.
One's complement is something
you should be familiar with.
It basically means you just flip all the bits.
If it was 0010 then you
>> flip all the bits, it'll be 1101.
>> You might go, "That's pretty simple."
Two's complement is where you flip
all the bits and then add 1.
If you had 001
and you flip all the bits, it would be 110.
If you add 1 to that, it would be 111.
I'm talking about all this in terms of binary.
You might think, "Okay. That's weird.
Why would you ever use that or need that?"
It's used for negative numbers.
It turns out that if you store
negative numbers as two's complement in binary,
you can use the same circuitry
in the computer for addition and
subtraction and other operations
if a negative number is in two's complement.
It's pretty nifty and it's a shortcut
that the hardware designers took to
make computers really fast and not have to have
extra circuitry for both negative and positive numbers.
You'll probably never see it though,
but it is something to be aware of in case you say,
"Oh, the output of this function,
was 11111111," then you
see the output from a print statement be negative 0.
It's just like, how do you have a negative 0?
It's like, well, technically it's possible to flip
the sign bit and it
did not have one added to it so it's negative 0 and
then negative 1 would be 1 on top of that.
I mentioned earlier, endian is important
and it's strange and rather
confusing and Intel is
>> really the only one that does it,
>> that I'm aware of.
It means it swaps the bytes.
The references come from Gulliver's Travels
where he came across a land of
small people who were fighting viciously
over what end to crack the egg from.
Little Endian, it does exactly what you'd think,
where the value is, 1, 2, 3, 4, 5,
6, 7, 8, and it's stored that way,
where it's stored little end first.
Little Endian is the strange one in that,
the least significant portion is
stored in the lowest address.
Example is 1, 2, 3, 4, 5, 6, 7, 8.
The bytes are swapped, so it's 78, 56, 34, 12.
Intel is Little Endian.
It's like I think
the only one that I've ever seen that's Little Endian,
maybe AMD is but I don't think so.
Big Endian is exactly what you would think it is.
If the value of a number or a spot in memory is 1,
2, 3, 4, 5, 6, 7, 8,
then it's stored like that.
This is when network traffic is being sent
across whatever device is sent as Big Endian.
If that's the value,
then that's how it's stored in memory.
Intel does this because at
some point they found it to be more
efficient and they could do operations faster.
A visual representation of
this would be something like this.
Little Endian is on the left,
Big Endian is on the right.
If you're still a little confused,
I'm going to do an example right
now. We can take this number.
I'm going to have to do this.
If we take this number,
I'm going to split it up into
two eight bytes sequence, so 0x11AB44FF.
Then the second value would be 0x
for hexadecimal, AADD1221.
Then I'm going to swap bytes, so 0xFF44AB11.
Then the other value would be 0x2112DDAA,
then we combine them back again.
[NOISE] This value in
a register would be in
an Intel Little Endian system stored as this value.
I would suggest practicing
>> it once or twice if you want.
>> Just some notes for the paranoid.
As I said earlier disassemblers can be wrong.
It's an unsolvable problem.
Without actually executing the code,
it's impossible to know
exactly what the instructions will do.
Sometimes malware do things that will
break disassemblers or trick them.
One good trick that I've seen is switching
from x86 assembly code to x64 code,
which you can only do in a 64-bit system.
But no disassembler or
>> debugger right now can handle it.
>> They just get disassembly wrong because they make
certain assumptions about the
code that they're processing,
and also jumping into the middle of other instructions.
There are programs out
there that very purposefully take advantage of
the assumptions made by disassemblers
to disassemble some code
so that it looks like a bunch of move instructions.
But what actually happens is that
a jump instruction jumped into
the middle of one of those instructions,
and it's actually executing something else.
Also, when you statically disassemble something,
you make an assumption
that you're reading what is going to be executed.
But malware will very frequently change its own code.
As it's executing,
it will change the code ahead of it to jump
somewhere else or to
decrypt something and then jump into that,
and we can see an example of that
here in the next few videos.
It's pretty interesting because we might have
to dump it out of
memory and then use a combination of
static and dynamic analysis
to figure out what's going on.
Some malware will statically compile
the libraries it's using into
itself instead of relying on the print f function,
being in a library that we can access.
Malware authors will include the C standard library.
Like it will include the entire stdio library.
That means that our five instruction or
10 instruction analysis just
turned into millions of instructions.
IDA Pro and others will try to
identify frequently used libraries,
and then try to label them and just say,
"Oh, his is string length or this is a string copy,"
but it doesn't always catch it.
There's a lot of malware out there that'll
have what's called junk code,
which functionally does nothing.
One of the first pieces of
malware that I was looking at for a
good long while that I just spent a week on,
had a lot of junk code where it would
make function calls like get system time or get
system information and
>> then jump into functions that just
>> had a lot of move instructions
and a lot of jump instructions.
They didn't really do anything,
but bury somewhere deep in one of
the calls that it made was code to unfold,
decrypt some other code of the payload,
and then it would use
another function call to jump into that.
That's not uncommon.
But once you look at it for a while,
you start to see some of the patterns
that those kinds of tools will produce.
I've seen one thing
that would go into an executable and just
insert random instructions like MOV EAX,
EAX or exchange EDX and EAX,
and then exchange them back a few instructions later.
It's code that guarantees
that the function of the program doesn't change,
and you can see that it's pretty easy to
associate meaningless instructions with
certain programs like packers or cryptus.
When we're talking about PUSH instructions
as it's loading up parameters,
keep in mind that the compiler is the
one generating these instructions.
Compilers don't necessarily have
to follow those conventions,
but it does when it has to interface with APIs.
Internally it can load up,
like we saw with 64-bit code,
it could load up the parameters and registers.
But when it comes to actually calling system libraries,
it has to have the stack in a good situation.
It has to have it in a good state
if you want that API to work.
We will take a look at some malware
which corrupts its own stack.
It's malware that we've already seen
before in prior videos,
it was that little IRCBot malware.
We'll take a look at that, and
it's going to be interesting.
There's many, many ways to do this stuff.
Luckily, most malware does not try to be super tricky.
Most malware authors aren't very sophisticated,
and most malware authors frankly just don't
care if they develop
a new anti-analysis technique or
an anti-debugging technique, or that
they spend a week developing a new way
to push and pop parameters on and off the stack.
That may be good.
It might be better in defensive measures.
But it would take them a week or
two and it would just take you
like 15 minutes to figure out.
It's really not a great time trade-off
for the malware author,
especially if their malware has already been analyzed.
That means their operation is probably already blown.
The pay on their motives is usually not time.
Depending on the malware authors motives
and depending on the purpose of the malware,
it's usually not advantageous for malware authors to
put in a whole lot of defenses into their malware.
Just a recap and a list of
good resources that I suggest you check out.
We went over the goals of stack analysis.
We want to understand what's going
on underneath the hood and we want
to find out more information and get
IOCs and confirm dynamic analysis.
Really want to gauge the sophistication
and maybe eventually attribution
of the malware and the attempt of the authors.
We went over a lot of
technical details on x86 assemblies.
I highly suggest you check out
how different control flow structures
and different data structures compile down,
and what the resulting assembly is.
Like how a switch statement compiles down,
or how nested if statements compile down and see
exactly what methodology the compiler
is using for optimization.
There's a lot of different ideas about how to do this.
If you are interested in that,
I would suggest taking a look at The Art of Assembly.
That was a pretty good book.
It's relatively neutral in terms of looking
at x86 and how to do things in terms
of looking at ARM and how to do something.
Also Reversing: Secrets of Reverse Engineering.
That is a fantastic book.
Some people think it's a bit dry and boring.
I think it's fantastic for what you want to do.
The IDA Pro book,
it's the unofficial IDA Pro book,
but it's the only IDA Pro book and it's pretty good,
especially if you're just beginning.
I would also suggest checking out
websites that hosts what are called Crack Means.
They are meant for reverse engineers
and crackers to figure
out key generation algorithms
or how to manipulate a program into
getting the information that you want.
Miter puts on a fantastic intro to
x86 at their open security training.info website.
They have all the materials up there,
the slides, challenges,
and videos up on YouTube.
I'll post a YouTube playlist.
I also suggest checking out
the Wikipedia x86 assembly language
and the x86 calling conventions.
Calling conventions is something we didn't quite cover,
but we will go over in the future.
It's basically how functions clean up
the stack before and after they enter a function call.
Sometimes the function,
the call e will clean up the stack.
It said, "I'm going to make 500 bytes
for my own local variables."
Then at the end, it cleans
up the 500 bytes off the stack.
Then sometimes in other calling conventions
like standard call,
the caller cleans up the stack.
It's like, this function is going to need
500 bytes for its local variables,
I'm going to give it 500 bytes on
the stack, call the function.
After it gets back, I'll
clean up the 500 bytes, I'll clean up the stack.
That's just what that is.
Thank you for watching.
I highly suggest you go explore on your own.
If you're interested in this stuff,
I would suggest checking out
malwarestats.org and you can see
how many malware samples they have doing
anti VM or anti disassembly techniques.
You can see what function calls you're using.
I highly suggest you also check out Corkami,
>> all his information.
>> He did a great job breaking down
the PE format and
displaying it in a very understandable way.
He goes through a lot of the values in
the PE file format and he messes with them and he says,
"This one does this, this one does this,
this one doesn't do anything even though
Microsoft says it does."
He shows how much you can mess with
a portable executable file format
before the operating system refuses to try execute it.
Malware will use a lot of those same type of tricks to
avoid automated analysis systems.
We'll take a look at that stuff in the future as well.
Thank you for watching and
hope you follow along to the next video.