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