>> Welcome to Cybrary. Hi, my name is Sean Pierce,
and I'm the subject matter expert for
introduction to malware analysis.
Today we are going to be covering
the basics of stack analysis Part 4,
where we will actually be
reverse engineering a piece of malware.
We're going to be looking at some of
the tricks commonly imposed by malware.
Sometimes in an effort to break disassemblers,
sometimes in an effort to just be
confusing or make analysis more difficult,
whether it be automated or just to try to trick a person.
We have looked at illusion bot before,
we looked at it last time.
I'm going to just extract it here,
which is something you should be a bit careful
with. Be careful where you click.
I'm just going to hit F2 and
rename these files so they
don't accidentally get executed.
I'm going to pull up IDA Pro and start
analyzing the botbinary.exe because
that is the executable that actually does the infection.
Some pretty fast analysis.
Here, we see something immediately down here in red,
it says SP analysis failed.
That's the stack pointer analysis.
Last time we're talking about
the stack a lot and we're talking about how
the compiler will generate
instructions to clean up the stack or make
functions that will save
registers and then push them in the beginning and pop
them off at the end or will do things
so that it can clean up the stack before
after different functions called depending on
a standard call or [inaudible].
Here, we can see this very basic trick
where a lot of very basic disassemblers will just break,
is where the stack
doesn't match up from beginning to end.
We see here, push ebp,
move ebp, esp,
standard introduction to
a standard prologue to a subroutine.
Then there's no minus esp.
I'm not making room on the stack
except it is doing this push, push, push.
Usually, this is done in
an effort to save these registers.
But you'll notice there's no popping here at the end.
It does this load effective address
and it does this subroutine.
But the location to the subroutine,
I figured out this was executable code,
puts it into this address,
and it pushes this address,
and then does this return.
Now, think about that for just a minute.
The return instruction will go and find
whatever return instruction it thinks it's supposed to go
to because it thinks some function call called it,
so it has to return to that address.
It will be this.
The return instruction, once it executes,
it will actually execute this function.
If we hit Space,
we can see that there might have
been something else down here, maybe code.
I like to hit C and find out.
I'll try to analyze it as code.
But it seems like it failed.
I'm going to switch over to this hex view,
which is basically hex editor.
I like to look at this data here.
These data in between these two functions,
these two bits of code.
I like to usually look to see if they're strings
or any usable data or if it's random junk.
That looks to be random junk
because there's no references to
it so it looks just from the side of it,
it looks like there is no part
of the program trying to access it.
But it could do that dynamically because like we said,
"There's no way to know
what the code is going to do until
we actually execute it."
Here, I recognize that there's a reference to this,
and it was likely some code.
This is the function here,
so I'm going to hit N and call this realMain.
We can see that it's also called right here.
I don't know how this code gets executed at all.
I'm going to hit X to see if there's
any references to it and there's not,
not at least the kind IDA is found.
That might be interesting,
but it's not important to us right now,
so we'll look into it later.
I'm interested in what this function does,
what the subroutine does.
It was more proper.
It looks like it calls three functions and it uses
some strings like Win98 so perhaps it's
testing to see what version
of the operating system it's using.
Now, we see this constant here.
That would be something I would google for.
Perhaps someone else has done
some analysis that we can leverage.
I keep looking down and I see
this registry call or see this path.
We can see this.
But notice that there's
no names in any of these functions.
That's not uncommon,
especially if something statically linked.
But what is interesting is here,
it's calling a dword.
Usually you call addresses,
but there's dwords here everywhere,
so that means it's data.
At some point this is manipulated.
I like to see what's there.
We look at it and we see it's just a reference to
some memory address that hasn't been filled in.
I'm going see what references are to this memory address.
I'm going to hit X and
see there is reference in three places.
Here, we can see on the right-hand side
the instructions associated with it.
One instruction, this move instruction
is the only one that writes to it.
That's curious.
The only places modified
in the whole program is right here.
I don't click on it and go to it.
This is very interesting.
These are all function calls.
There's this GetProcAddress function call
here and if we scroll up,
we can see there's this LoadLibrary address and
it's loading these DLLs.
It's getting the functions it needs from these DLLs,
rather than have all these DLLs
or all these function names
populated in the import address table.
Under import, we see this actually just
using a few of these function calls.
You only need to LoadLibrary and
GetProcAddress to resolve all the other function calls.
LoadLibrary is used to get a handle to
a library and then GetProcAddress is
used to get the address
to that function call, as you might guess.
We can flip back over here
and we can start looking at this pattern.
LoadLibrary is called,
it needs a parameter.
It's doing the same move as doing the same push.
It looks like eax was being stored in bar 8.
We can see that LoadLibrary was called up here as well.
I'm going to say there is
a push wininet was pushed onto the stack.
This move doesn't really affect
that and LoadLibrary was called.
LoadLibrary was called and a handle was returned.
A handle was put into eax because remember,
eax is what a functions return.
eax holds the value of whatever the function returned.
There is a GetProcAddress
and it's moving that into
esi because LoadLibrary is not using it anymore.
It's going to push two things,
ebx and a ProcName
and move eax into var 4.
eax was last modified when it called LoadLibrary.
We now know that var 4 is the wininet DLL handle.
I'm going to just say handle.
GetProcAddress will return a value in the eax register.
If you look at that,
it'll be for proc
and that's a pretty standard Windows API return.
But what we really want is the dwords to
say send or whatever else.
If we want to GetProcAddress
here and store the result in eax,
we can guess that send,
the function address for send is stored there
[NOISE] and make it a little
clean and say, [NOISE] function send.
Let's double check that, so GetProcAddress.
It'll return. I think it returns.
Oh, the good thing about this is,
we can always google [NOISE] and check.
[NOISE]
Retrieves the address of an exported function or
variable from the specified dynamic link library or DLL.
>> It takes in two parameters,
each module, which is a handle to the library,
and a long pointer
to the ProcName as a long pointer C string.
If it succeeds, the return value is
the address of the exported function,
so yes, and if it's null,
then it failed, but there
doesn't seem to be any error checking.
We can see this pattern,
ProcAddress was called,
so we know that eax was then the send function.
Let's see. ProcAddress was moved,
so last call was the library.
When was this receive used?
Pushed the each module, called get ProcAddress.
This send was a parameter to the next one,
and this receive was
actually the parameter to this get ProcAddress.
That makes sense. This was actually receive.
What tipped me off to this was it loaded up wininet,
and then used this string.
Send and receive are pretty common functions
used by network-aware software,
and they're pretty common in malware as well.
We can continue the same type of process
where eax was answered here,
send was the next one, so function_send.
Good to be consistent. We could
do all of this down the line.
If you're really good,
you can use IDC or
Python to write a small script to do this for you,
but what are we really after again?
Well, we might like to know a Mutex that's created,
we can see it's pushed,
it will be the parameters to this.
We now know that eax is a result of GetProcAddress,
so we know that this is
CreateMutex A. [inaudible] I'm going to say x,
what else uses this?
Only two functions uses this,
so if we see here call CreateMutex function A,
there's three parameters that were pushed.
This one being the first,
I'm willing to bet that if we Googled CreateMutex A,
the final parameter, the rightmost parameter,
will be the name of the Mutex.
I'm willing to bet this is probably zero, yeah.
Xor ESI, ESI,
so the zero rules out ESI,
compares it to something but reuses the value down here.
So it's calling CreateMutex A 00, and then this value.
Let's Google that Mutex A.
If you see these functions like Message Box,
Message Box A, Message Box W, CreateMutex,
CreateMutex A, CreateMutex W,
A at the end stands for ASCII,
W at the end stands for Unicode.
I don't know why. Anyway, I was right,
the rightmost parameter is a long pointer C string,
and it's pointing to the name of the Mutex.
This is another indicator of compromise.
If this Mutex appears on your computer,
then you might be compromised with this piece of malware.
This is pretty good knowledge to have when you're
fighting malware because I
pulled that out in a few minutes.
So if your organization had
the capability to search across your entire enterprise
for all running Mutexes
with some software like [inaudible]
or whatever agents are listening on your devices,
you could immediately pass that over
to a hunt team or something like that,
or the SOC team or whoever
does that, and you can say, hey,
I'm not done with my analysis,
but look for this Mutex and then you can keep going.
I'm interested to know what part of the program
is checking the Mutex
to see if there's another infection going on,
and we can see that it was called by realMain.
If I'm not mistaken,
realMain also called CreateMutex here.
So is this the same string?
We hit Escape and we can just go back,
forward, back, forward,
back, forward, back,
it looks like the same string.
It's checking in two different places and it's code to
make sure another instance of infection isn't running.
I'd like to know what this code is because depending
on what the CreateMutex A function returns,
it's going to do something else,
because it makes another function call
and then compares the output of that to this value.
I'm going to go find out what this is,
it's only written two once, eax,
eax was modified by
this call instruction for GetProcAddress,
and the parameters to that ProcAddress was GetLastError.
That's pretty useful. It's probably called
in more than one place.
Following that path of logic again,
GetLastError was pushed as a parameter to call this,
and which affected eax,
which was inserted into here,
Get Last Error, and then it compares that to B7.
Do some more Googling, say Windows error codes.
Let's just say, I hope they have hex, 0xB7.
Perfect. Error_Already_Exists. We know
that it's comparing that to Error_Already_Exists,
and if it already exists, it does this.
This is probably exit process.
Terminate or do something else.
Another cool trick we can do with
either is we can say, hey,
I know this is that Error_Already_Exists enum,
so we can actually specify that here,
use standard symbolic constant or the M shortcut.
It's going to bring us a list of
all of the enumerations that it knows of.
Here it knows that
Error_Already_Exists
matches this value, and then click "Okay".
It makes it a little easier to read.
GetLastError already exists.
May as well figure out what this is.
It's written to here,
and it's written to here.
That's very interesting.
Let's check this one out.
That's the location we already are at, that location.
CreateMutex A it stores the value here,
and the result of CreateMutex A.
>> I search for returns.
As the function succeeds,
the return value is a handle to
the newly created new text object.
As the function fails, the value is null.
I'm going to say Mutex Handle.
That's a local variable.
I want to find out what this
is apparently is called a lot.
We should really label that function.
I'm going to figure out what this is,
the EAX was modified by GetProcAddress here,
which had the parameters of CloseHandle,
changes name, or I guess I should be
consistent and say function
CloseHandle, but that's okay.
I'm going to name this because I see it quite frequently.
FunctionTable builder.
No, it's not really a table.
FunctionResolver.
We can see who calls it realMain, that's right.
Calls it right there has the first thing it calls.
We can pick apart this program bit by
bit and really get into exactly what it's doing.
We can totally understand all of its capabilities.
But before diving in,
you should really ask yourself,
what am I after?
Am after indicators of compromise,
am I after network traffic,
am I after authorship sophistication.
Because it's easy to get
lost in the details because you have
a very detailed view of everything.
You can easily just go down rabbit holes.
You can go off into the weeds,
you can take whatever analogy you want.
But early on I said,
this is very detail-oriented
and every once in
a while you need to pop your head up and say,
''Okay, what am I after again?''
Because this malware was found on the machines.
What's its capabilities?
I can go for that.
A good way to determine its capabilities.
After you've already gotten a look
at what it's doing to defend itself,
would be to look at the function calls it makes.
We can see the hostname, we can do some.
We can say, "Okay,
let's doing something with the network."
I can delete files,
I can read files,
I can create files.
It can modify the registry.
We already knew this from art dynamic analysis.
We saw that it modify that registry.
It opened a whole new firewall for itself.
We saw that it
could take certain commands from the IRC server.
We can see virtual free virtual allies
is important because it can create memory which
include insert code into and then use
the VirtualProtect function to execute
that code and search directories.
This using some ZW functions,
ZW are usually reserved for lower-level libraries.
They should never be called by
higher-level user land programs
unless you really know what you're doing
and even then you probably shouldn't do it.
This guy is using this function.
I would be curious to see how he's using that.
Because it's probably an anti-debugging method.
Because you can call
this function and you will get back information
about your process or
your thread or any other processors or do you want.
You can determine from the kernels
response if that thread process
or whatever is being debugged.
I'd be willing to look into that
>> if I wanted to debug it.
>> Say OpenAddress Registry stuff.
It can also mess with services.
If I didn't know any better,
I would be like, okay,
it's probably installing via
service and if I wanted to go
down that rabbit hole and
determine the service name it's using.
I could do that with these functions very quickly.
I could just say,
"Oh, where is this thing being used?"
It's only being used in one function
or it's being used here.
I can look for any strings around there.
I see none. I go for another one.
But if I wanted to follow that rabbit hole, I could.
Now here's some more interesting strings.
It's interesting because there's a slash, slash,
and escape slash in there. This is interesting.
P colon slash slash and what looks to
be a file name extension. This looks interesting.
These look like encrypted strings, basic obfuscation.
It looks like it's pushing these.
Moving a value into d word x is modified by this.
This is delete registry handle here.
It's GetProcAddress.
This was the last of these,
but it calls this after is received.
The parameters of the pointers
to these strings and it's called
multiple times and each time there's
a obfuscated string and a different location.
I'm willing to bet the string is input.
Dysfunction is decryption or deification,
and this is output.
Let's take a quick look into that.
I'm going to say decryptString,
takes in two arguments,
two pointers is what it looks like.
Sores on an ESI and then stores this one
in EDI system to AL,
which is the lower eight bits of
the 32-bit EAX register, if I'm not mistaken.
This is useful if you just want a character.
Test AL means it tests to see if this is zero,
so test AL is the string blank.
If the zero flag was active,
it was a 1-bit in there.
It will skip to the end so a test to
see if there was any characters in that string.
If that string had a character in it,
then it would begin executing this loop.
Where does the push increments,
ESI, the source index?
It calls this function.
It moves AL and to
EDI and then moves it into ESI increments EDI,
pops the value off the stack into ECX,
and tests it to see if it's zero.
If this is not zero,
the jump is taken.
This is taken.
It means conversely, if it is zero, this full circle.
We can hit space and say,
if the value is zero,
then just falls through to
the next instruction, which is down here.
[NOISE] You can see
this function has something
to do with these lists decryption.
We can pick at it really quickly and say,
"Okay, there's an alphabet there,
and there's an alphabet there."
I'm just going to guess just by looking at it.
It's not really an encryption off
your cation is really more of an encoding.
It does a simple swap.
You can double-click it and dive into it.
There's the basic function prologue,
mixed space for local variables.
There is a push, push, push.
This is interesting and
it would take a few minutes to figure it out.
It wouldn't be too hard and
we could even write our own version.
We can decrypt the strings ourselves.
However, in the next video,
I'm going to show you the easy way of doing it.