Kyle Gwinnup –  Next Generation Process Emulation with Binee – DEF CON 27 Conference

Kyle Gwinnup – Next Generation Process Emulation with Binee – DEF CON 27 Conference


>>Alright so Kyle and John are
going to talk about process
emulation they’re all the way in from Boston so this is of this
heat for them with and luckly
they haven’t melted on lets give these gentlemen round of
applause>>Thanks everyone for
coming so like he said this is about process emulation in
particular automating that
process emulation at scale so before we get started I want to
talk about is kind of like how
we think about analyzing all the malware and all the binaries we
get and in particular we have a
fairly large ingestion pipeline and we need to be able to
process all the samples quickly
and efficiently. So when we think about a sample uh what we
think about is a every sample
has some new finite amount of total features or data that can
extract out of it and all those
pieces of information cost a little bit different and have
different cost with each one. So
when we talk about the cost the reason that the cost is there is
because as you see in the graph
we have static the two the two domains of extracting
information is static and
dynamic, so static is obviously the cheapest and the fastest and
you know the primary reasons
that you can just do that at scale very easily throw it in
Docker or your function service
whatever cloud provider and you can just extract those features
really quickly. Dynamic of
course is the opposite of that it runs very slow spin up lots
of machines, you have to
configure them in particular ways and just um increases our
cost for getting information. So
as we collect more samples particularly when malware comes
in, there’s some problems with
that right so, when doing this research we we really have with
three problems we want to solve
particularly with regard to malware I and the first one is
obsfucation and packers and
encryptors and then to a lesser extent different types of
installers and what these have
the effect of the effect to do is they actually limit the
amount of information extract
from static analysis so they reduce that total set and then
would force us to do is push
those samples is not getting all the information you want from
them were forced to push those
into the dynamic analysis domain but the dynamic analysis domain
you know is more expensive and
increases our cost which is not something that we like. But the
dynamic analysis domain also has
some problems right so there is anti-analysis techniques, like
no malware likes to be like run
in a debugger, like on a different type of hypervisors.
But effectivelty there’s this
infinite set of like cat and mouse kind of things things that
you need to add to the to the
machine to trick the malware into thinking to to run. In
addition not all malware is like
equal opportunity, it doesn’t run on every machine equally
some malware is targeted, so it
won’t run the same way on a Windows machine in English as it
would you know in French machine
or some other keyboard or any number of features in there. So
the old one with those three
problems in mind, that our goal is to basically we have three
goals in mind first is want to
reduce the cost want to bring the the static analysis features
that we lost to obsfucation, we
want to remove those from the uh of the dynamic domain and bring
us back into the static analysis
who want to come bring back parity of static analysis or at
least the cost of associated
with that and in the second they want to do and this is your we
hope to bring as much as we can
we really want to do is to take some of the features you would
find inside of dyn.. dynamic
analysis domain and emulate those or bring those back into
or bring those into the static
analysis domain increasing like the total set that we can
actually extract via static
analysis or at least more than traditionally you would accept.
And the last thing of course is
we want to do all this at scale so the static analysis kind of
implies the scale but we want to
make sure that we can run all these things inside of Docker or
inside of your functions
service. So with that we came, explored several options and
what we decided on the
simulation, and anyone’s not aware there’s a really amazing
emulator out there right now,
Unicorn Engine, this basically CPU architecture emulation but
they also emulate memory and
this is key so what we want to do is we want to load up malware
and want to replicate the
Windows process memory inside the emulator is with as high
fidelity as we can and what this
allows us do with the emulation in particular is we get full
introspection into every single
instruction on the system I’ll be at full introspection to
system call so we can hook
everything and then what that also allows a dues because we
can hook everything and we’d see
everything we can also mock out more of the system and this was
key and this was where we feel
like we were adding a lot of value is we took kind of an idea
from unit testing with software
engineering where you’re mocking out functions and services and
we thought why can’t we just
mock out large chunks of the OS to allow the malware to execute
further than we would normally
expect. So with that there were other PE emulators that are out
there three at the top were
found on the unicorn website and these are pretty nice right,
this is where we got some
inspiration and what they do though I should take the PE file
load up a bunch of DLLs and I’ll
actually throw it into the emulator space and execute them.
And they do every well- they’ll
output you get the parameters for the functioning of the unit
where they’re called what the
function name is and the return values. And they work they work
quite well and we want to see
all right, using this as inspiration how can we take this
like the next step further so
with that kind of in mind, we had some requirements for when
we decided what we want to build
right, so there is one extra requirement is one of the code
to be simple so wanted to build
this framework for executing and that the actual code be very
simple and when we originally
POC’d this we did it in C and then to make it even more
accessible we we switched to
Golang, so that’s just as a side note, but in the four core
requirements to be anywhere, one
we wanted to come to formalize that mechanism for loading a PE
file and all of its DLLs so we
like sync all them up, get the imports working in when a call
is made it actually jumps to the
real DLL within, or the real function within the DLL that was
called. So once we had that then
we can really build a good-hooking framework and this
is good.. the hooking framework
is really the core part of of any and it enables everything
else and we wanted this to also
be as simple as possible so when you want to define a hook you
just basically fill in a
structure that defines the name of the hook, the parameters and
the implementation and then the
third thing because of that do we want to extend the current
research a little bit and then
add your mocking out some of the some of the OS so a lot of
malware you touch the file
system, touches the registry, has threads things like that,
what if we could actually mock
that inside the emulator and make the malware think that it
is actually running and inside
of a real PC and this what this really allows is to add more
fidelity to some of the function
calls and really take the next step we think of in the PE
emulation space. And lastly want
this to be highly configurable so we want.. with the problem of
dynamic analysis right, is that
you have kind of an infinite array of cat and mouse and
figuring out you know, the
anti-analysis techniques and like the whether malware will
run on the machine, so we want
to do is find a single configuration file that
represents the entire
environment of the machine so the entire context with the idea
that we can enumerate a bunch of
different configuration files and we can run Binee against a
particular sample much faster
against the hundred you know, configuration files than we
could spinning up 100 different
enumerations of those machines so that is you change the
keyboard change the registries
and then you can do this kind of very rapidly and then you can
take have the malware take
different branches, and then just really explore what it
actually does. So with that, now
we’re going to talk about the implementation details of Binee
and while we’re going through
this, so lil.. quick history on Binee is that it started just
like a side project, we’re
looking at those three examples I showed you from the Unicorn
website and we’re just kind of
playing around with it, throwing the PE in the emulator seeing
what it would do and then
eventually we got to this point where we were actually getting
interesting data or useful data
and then we decided it was a actually worth pursuing as a as
a real project and now is
actually living inside of our ingestion pipeline and
everything goes through it. So
this is a.. this talk will be from now on, kind of like a
little bit will have some
screenshots and some demo stuff we’ll do official real demos of
the end we’ll have screenshots
of that and explain what we were talking about you and slides
prior to and this will be in
chronological order of of the different problems that we had
when we are running different
samples through. So you know, with that said what’s the first
problem when you’re building an
emulator like this, so the first thing is you need to write a..
you need a parser to parse the
PE files need something to parse the DLLs and in all and all the
get all the information out of
there and need to be able to link that up and throw it in the
emulator. So first we did was,
of course, wrote a parser. Wrote a PE parser that would you know
parse our PE file, DLLs and then
we added some, the reason we wrote the parser is cause we
wanted to do all of the linking
and the updating of like the base address and you the imports
and various other features,
wanted to do that all outside the emulator and the main reason
to do that, once we get
everything in the emulator we only want to start the emulator
once. We don’t want to interact
with the emulator a bunch, it’s just it’s more time-consuming
kind of problematic so writing
our PE parser and in getting that going you basically, you
load the P,E you get its imports
tables recursively and you go through and you get a load of
all the PEs and then you update
the base address of the DLLs and then once those are all synced
up then you throw that in memory
and one of the reason we want to do this outside of the emulator
was because for every DLL, once
we finish linking everything up we go back through every DLL and
grab the exports so we let we
now we know where the real image at image is for the addresses
for particular function in the
memory space an now we’re going to build our own map outside of
the emulator, that has a map
between the of the DLL, the function and where the address
actually is in memory and this
is so we can enable the hooking, so when the emulator actually
jumps to that address we know to
stop the emulator, run our hook if if there’s a hook available
and move on. And you think of
this work right away right done on modern on modern binaries or
modern Windows machines there’s
these things called API sets, so you compile when binary on
Windows anything after maybe
Windows 7 I think some service pack in there, you’ll actually
when you you you pound a,
include a particular file and you do like load library in this
case is a screenshot indicates,
you’re not going to get the real DLL ,else so we didn’t actually
know what the DLL was.
Fortunately Jeff Chapelle has some amazing documentation, he’s
in a lot of RE work on this and
we were able to pull that implantation directly into
Binee, and add this to our PE
parser. So now when our PE parser get this kind of file it
grabs that that full API set
grabs the API sets’ schema DLL which is in every version of
Windows beyond, I think, seven,
which is the lookup table for the actual real DLL on disk, so
now we can do the real linking
and load all this into memory space, so this is kinda the
first problem that we had. So
now you we have the PE file inside of memory, we have all
the DLLs linked up, we haven’t
quite hit go yet, but the next thing we want to be able to do
is you were mocking kind of the
system right, doing unit testing of the malware effectively, so
we don’t need to implement you
know, all of the Windows subsystems of course that would
be painful but we can influence
subsets of it.. but at the end of the day what we will really
want is want the malware to
think that this particular API was executed successfully. Like
we don’t really care that, about
it, like all the other details of the API, we just need all
right, does this function return
a value? Is that value, what does that value need to be in
order for that the malware to
continue executing? So, in the case of like create file, all we
really need here is we need to
pop some values off the stack and then we need to put a valid
address or a valid identifier
and EAX. So basically, not -1 there, then the malware will
continue thinking that is
executed successfully. So that brings us to hooking. So I
mentioned the hooking, we wanted
it to be incredibly simple and you know, we believe it is, so
when you define a hook, as I
said earlier we have we have a mapping of all the hooks were
the addresses actually are and
what you do is when you’re want to implement this inside of the
inside of framework you define a
type of struct you know describes your hook, and all you
really need is the name of the
function you want to hook, the parameters which is just a
string or array of strings and
they also accept format string variables which I’ll explain on
the next slide about you know,
display and then the last two are optional, uh, function are
optional parameters? So if you
define the function this is the actual implementation that you
would be over overwriting and
then the return value. Em.. if you don’t know if you don’t have
these and just assume it’s own
default behavior. So with that then we ended up with two types
of hooks. There’s a full hook
where we actually override the implementation of the DLL so
when Binee is executing inside
PE it goes to a function call so in this case it hit sleep and
then what’ll happen is ill do
it’ll call instruction to sleep into kernal32 or whatever and it
will go in that address in
memory and then what happens is when we hit that address because
we have them all, we have the
lookup table, we’ll hook that address, stop execution and run
our implementation which then
can you know, either override it in a full hook case or what I’ll
talk about in a second is
partial hook. So looking at that, so this is the only way to
define this hook is used to find
the name which is sleep, right? And then you define a pointer to
the hook in which contains the
parameters which the string and the function, and one thing
everything is pretty cool here
is, particularly with malware, is doing like a sleep very early
on, you know sometimes it’s
trying to evade something, so sleep in this case we can
actually intercept the
parameter, so with our function implementation you get two
parameters that are built into
it and those pass in the context of what the functions called, so
basically the parameters that
it’s called and some other, you know, metadata.. and we can do
is we can just increment the
tick count of the CPU and then just return immediately, and
then the malware is just like
okay we must execute successfully we slept for five
minutes or whatever and it can
go then call, gets tick count later and then it’ll actually
get an incremented tick count.
So this will happen in real time it’s just right and it’s just
instant. So that’s a full hook
but unfortunately, we don’t want to do.. fortunately we don’t
want to hook everything because
it’d just take forever we really only want to hook things that
make a system call. So for
everything else that doesn’t actually make a system call and
transition in the kernel mode we
just want to do is.. we call partial hook and effectively
what this does this just gives
us the details of the parameters in like a human readable form
for that particular function and
so what happens here is when the functions call that jumps into
the DLL that’s that function
within the DLL and it literally emulates that function and then
returns back to the PE file as
normal. So as I mentioned the parameter skills is that this is
a particularly important field
and it actually does like three things. The first is it defines
the string values it sets the
parameter names so when you output is the kind of in the
bottom part of the screenshot it
will give you the human readable values to the screen so this is
this information it will capture
in the data pipeline. The second thing it’ll do is it’ll it’ll
dictate what gets popped off of
the stack so when you return for a function it’ll actually say
allright we have some helper
functions built in that so if you go back a slide the skip
function standard call that’s
built in and that’ll recognize how the parameters are on this
and this and this list and it’ll
pop those those values of the stack.. and it’ll do all this
for you. Um, and then lastly the
parameters are what’s used for when you call when you call into
that function you want access to
those parameters to do your implementation, this is how you
would reference them as you, as
they offset that they’re actually in. So a quick example
there will be several these
demos you throughout er, the screenshot demos throughout but
if we look at the highlight
lines, the first one is you were actually running Binee and we
have various parameters, so the
– V will actually say will spit out all of the instructions so
this will be like verbose mode
will give you all the instructions leading up to a
particular function call and
then the last line that’s highlighted is the actual
function call that we’re getting
so we’ve actually hooked it, right and you can see it’s a
different address so we know
that this is where the DLL was mapped this is where that
function is within that DLL and
then just next to the address there is a slightly different
than what PE is just next to
that address is an F and this would indicate that it’s a full
hook versus the partial hook and
knowing this is actually very useful for debugging when you’re
going through malware and trying
to get it to go to different branches but that is that
indication and then you get the
of the actual name of the function you know the parameters
and they can be in human
readable format they take a format strings parameter and
then of course the return value
which is also important. Perfect allright so now this point we
basically have a PE parser, we
have loading DLLs and actually everything set up to to a
certain extent we we actually
have some hooks properly implemented a hooking system
implemented and that’s all great
and this is where we kind of hit the feature parity mark for some
the other emulators that we are
that we were a kind of describing earlier and so we
asked ourselves are we done here
and of course not. So we’re able to access an entry point and
then start the emulator set
everything up as as mentioned earlier in the press go in and
continue forward and hopefully
get through most of the sample and have it terminate
successfully. Well in the case
of some of what we’re doing the partial hooking it wasn’t
particularly working properly
for us. In the case of like say GetCurrentProcessId as you see
on the screen here on we are
partially hooking this mainly because it wasn’t making a
system call and typically we we
only want a full hook functions that are making system calls
ultimately, and so in the case
of getting our process ID it was actually accessing Windows
UserLand objects and we did not
have those set up at all and so before we can actually go and
set up these UserLand objects we
actually had to implement segment registers that was kind
of a glaring oversight when we
first set this all up, so fortunately there’s actually,
thanks to Chris Eagle on that,
there’s actually a lot of examples on how to I do that and
so we were kinda able to take
the code that he had written and kinda take that in and make it
suited to our needs. So now that
we actually had the segment the segment registers we were
actually able to start filling
out windows UserLand and structures in particular, most
of what we’ve actually done is
like the TIB and the PEB which are the thread information block
and that the process environment
block respectively and we actually wanted to start filling
those out cause it turns out
that malware actually, any any program really uses those
extensively. Typically when the
Windows loader actually starts up process it will actually
populate a lot of these
structures so that the whatever’s running can actually
reference that and in many cases
uses the information so it doesn’t have to makes a a
context switch in to kernel mode
to get certain information, so we actually wanted to to build
these out and much like the rest
of the requirements Bineee Binee, they needed to be
configurable, so with that we
actually started building at the TIB and the PEB and at first it
was it was mainly just as we saw
fit um we’d see samples that would hit a certain portion of
of the structures and then from
there it would fail and we say okay were missing this this
certain field, and so we
actually built out the structures and these structures
are quite large for those of you
who have maybe seen it before these structs are quite long and
every version of Windows they
keep adding more and more to this so as we were kind of going
through the Windows versions
making we had all the information and these structures
actually ballooned in size quite
a bit, but the important take away from this is that we
actually again can only
populated the fields that we needed at the current time, so
most of what we did was usually
lowering the structure but higher-level stuff we kind of
ignored and would NOP out and so
if we had an issue we would then populate that and move on, and
again much like we did with the
PEs in the in the DLLs when we were parsing we are actually
setting up the TIB and the PEB
ahead of time and actually having it kind of in a
semi-working state before we
actually started the emulator itself, typically it’s done as a
loader is going but in this case
we we just kinda set it up ahead of time with mock values that
would kinda make the sample run
and be happy to go through what it needed to do. So now that we
actually had something going we
are actually getting through some samples it was is great to
see we actually got through a
few example programs we had written to test certain things
that we’re going from start to
finish we are seeing the terminate process at the end
which is great to see you really
exciting stuff, so then we actually came to a crossroads
where we want to actually
continue adding more to it like Colin mentioned with the
requirements there is there’s a
number of subsystems and that we want to mock out especially on
the OS level but before we can
do that we actually have to go and set up some some more stuff
that Windows would require and
for that reason we actually start doing start doing stuff
with handles. Windows uses
handles for a number of things basically anything you can think
of on like the lower levels side
of things like especially like file filing access, registry
stuff, anything with the
threading that that’s all done via handles which are
effectively just a memory
pointer to some sort of information in memory, and so
what we did was we basically
created like a superstructure of all of all the types of handles
that we might use and kinda put
them in one place and using the information we can then just
abstract away most of what
Windows would expect to have inside the handles and we can
then, hand wave and pretend that
they’re actually there an the malware or any sample we put
through it can actually go and
continue forward and we can we can then build subsystems on top
of that so it’s it’s kind of a
basic building block for us to kinda start building subsystems
and mocking out the OS. And of
course you can’t actually do anything with handles until
we’ve actually made a proper
memory manager, so we actually started to build a memory
manager inside Binee itself
that’d be kinda separate from the emulator and that we we we
take we took a normal Heap
implementation and kind of build it up to to suit our needs a
little bit more so it does
everything you would expect a Heap, in a heap manager and then
we kinda build on top of that.
The way we can handle the heap in this case is anything that
references the heap so say it’s
maloc or free some one of those function calls, what we do is
any library that was that was
calling some that some style of memory management on it we’d
partial hook and ultimately
whats going to happen is there going to hit ntdll and when we
hit ntdll then we’re actually
full hooking that memory management function and then
we’re passing it over to the
Binee memory manager and then doing everything from there. And
from there we can then start
doing more things than just you just heap management for example
everything that’s that’s not on
the stack we’re then just throwing into the heap and that
the member manager is taking
everything care of everything for us. So with that we can
actually start putting atomic
IDs for handles which will point to our superstructures outside
outside the emulator and the we,
from there we can actually having, have those the
structures filled out and then
from there build on top of it, so say we do file stuff registry
stuff etc. So that that’s all
now handled. So now I feel like at this point when we are doing
the development, this is where
kinda switched into where it’s a real project and were actually
we were confident that we were
going to get useful information whereas before it was kind of
touch and go, but basically what
that means we would mimicked the the UserLand space quite well,
right, so we have as John,
mentioned, we have a heap which is critical and then we have all
of the UserLand processes and
the hooking and place and things like that, so the next thing we
want to do is I’ll see if we can
actually capture some some files so we have a piece of malware
that writes a file can we
actually capture that and then save it and analyze later, so
the first thing we want started
implementing when we got into the mocking of the OS was the
file system, and the way we did
that as we basically Binee will have it, it kinda operates
similar to Windows where it.
when you’re searching for a DLL, when you load something is Binee
will have several different
paths where it looks for files. In the first path is its own
kind of folder when you so when
you start Binee you can give it a file path and will be its root
directory for where the the file
system is and then from within there you can actually copy in
your DLLs or copy of the other
files you want so when Binee actually does a create file it
will actually grab whatever the
file actually is and coming back to the hooking and so what does
the malware actually need
though, we just need a valid handle so we have a file, a mock
file system that can support
that the handles and in the abstractions that go along with
the with interacting with the
system. So with that, the first thing that happens is first of
all, all of the file functions
like create file all these things are fully hooked right,
cause eventually these would
make a system call and we want intercept all those things so we
fully hook that what happens is
we’re gonna hit that address it within that within the emulator
the emulator’s gonna know we’re
at some address that’s fully hooked it’s gonna popout, so
sim.. so similar to the
transition from your user to kernel space it’s gonna pop out
to our own filesystem handler
and then what’s gonna happen is its gonna instantiate one of
these new handles to pass in all
the parameters from create file so specifically the path and
that permissions and then with
that it’s gonna instantiate a file, create a handle put that
handling Binee’s lookup table
and then pass since Binee’s getting you a valid handle from
the heap which is going to be a
atomic address it to pass that back as EAX back into the create
file, so now when you run create
file you’ll actually get a real handle that than the malware can
can then use, or the file can
then use. But other thing we want to do is if we’re running
multiple samples within this
filesystem we want any rights like we don’t want to pollute
the system the file system or
the registry with anything we do but any rights need to go to a
our sandbox location, so if the
malware is installing some persistence mechanism or
whatever we want to actually
capture that so we can analyzer it later so if there’s anything
that’s created like a create
file with any type of write bit set Binee will actually
understand the hey, we’ref
trying to write here so let’s instead of going to the real
path they’re trying to write to
the real file they’re opening, let’s redirect that into the
sandbox location. So as I said a
write file will get called, it will get into it will get hooked
right cause we know the address,
and go into the fold.. the Binee system handler grab that handle,
write anything they were writing
to the file will actually just redirect it to these bins and
then it will just return how
many bytes were written written successfully and the malware
really doesn’t know any
different. Here’s a little screenshot of that actually
happening so of course the two
highlighted lines on the first one actually you know a create
file getting you the actual file
path it’s located and the permissions, so this is super
helpful when we’re doing data
analysis later is capturing all this data and this is the more
the human form running and in
manual mode there’s also – J option we can calculate this and
get it in JSON so, that’s part
of our ingestion pipeline but the important thing here is we
know the path right? We know the
permissions and then we know the return value and the return
value IS the handle, so the
malware actually gets a valid abut handle here, right it
doesn’t get -1 so the malware is
like okay you’re good so we’ll continue executing, now we’re
not in the sandbox and at the
end there, last highlighted line is write file, So now we’re, the
first parameter here is our
valid handle and then we know when we hit write file Binee’s
going to execute or intercept
that that call and then run its implementations, it’s full
hook.. And of course we’re going
to return a valid output for that which can be the number of
bytes written and then again our
malware doesn’t really know any different. So just in the
console you can LS the file and
everything goes this temp directory we created a mal.exe,
a malfile exe this is not a
valid EXE of course and then we just catted the bytes so we can
actually this is kind of like
when we saw this right yeah we can definitely we do something
with this and of course this is
a very trivial example and we’ll show some more in the demos of
real malware. So you know, we’re
just continuing on and this whole process very iteratively
just get a new sample of malware
an we execute it, see how far it goes and it’s like now we need
to implement a file system we
need to implement this.. so the next one that we needed that we
wanted to implement or we need
to implement was the registry and similar to the file system
every registry call is
eventually.. you drop in the system or in to kernel mode so
we want to full hook all of this
and then when we full hook those we built a registry within Binee
that has a bunch of helper
methods for you accessing the different keys in the registry
and then one cool thing about
this is we made it, we wanted to mimic being able to load any
value from your Windows registry
into the Binee registry we want to make as seamless possible so
you just export you from regedit
you can actually import all of that data that file that exports
they saved to disk you can just
copy and paste those into our configuration file and then then
Binee will just read those up,
so this is really useful if your malware is dependent on certain
keys or trying to evaluate
what’s what what its actually storing in keys and you can
toggle these in real-time and
it’s very fast. So you all registry keys are gonna get
hooked it’s going to get into
the Binney subsystem for handling registry you do
whatever option it or whatever
function that that’s required and then just return valid data
back to the malware and again
the malware has no idea. So the next thing we wanna do is
configuration files and as I
mentioned these are directly copied, the registry keys here
are directly copied from from
regedit from the export and then inside of Binee’s registry,
there’s a handler that converts
these to bytes for whatever the proper type this so, we’ve kind
of abstracted that awaits you
really have to worry about and that’ll just copy bytes back
into the emulator and it just
works you as you expect and the other thing to note, and kind of
one of requirements was this
configuration file needs to be very easy to edit and very easy
to understand on any kind of
all-inclusive so I just cherry picked a few values here but
there’s obviously a lot more..
the root filesystem, so this is how you define where the actual
files are located and this is
typically where we put all the DLLs and like NLS files in your
other files you want that are
supporting the execution and then you can also have like
codepage identifiers you know
what process IDs you have pretty much anything that would go in
the TIB or the PEB or that would
help the you know, the execution of the sample would go in this
one for and of course the
registry is defined like this and it will parse everything
properly and build the tree so
it’s a pretty efficient access. So again another quick sample
looking at the registry key we
have three you know highlighted rows your axis the registry key
will give great insight into
what’s actually happening and these are the IOCs that we
really want when doing some of
our machine learning and then you know the query values, you
can look at the particular.. the
value name and the next we can see what’s actually getting set
into this registry keys and
because this is again all turning returning back
successfully malware doesn’t
really doesn’t really know. So now that we actually have a few
subsystems we have file
subsystem, registry subsystem, we have configuration files to
kind of back all that up we
actually started running this against more and more samples
and we are finding some
interesting results in the case in the case of a few samples we
were hitting some some
interesting threading stuff and and in some cases we were at we
weren’t actually doing anything
with threading and we wanted to Binee by nature because it’s an
emulation what didn’t have any
sort of thread management so we actually implemented a thread
manager. When we actually
implemented this, we kind of treated it as a global
interpretation lock so it’s it’s
basically just a round robin scheduler everything single
threaded and we time sliced out
each of the threads so it’ll a certain thread will run for a
certain instruction… uh times
and instructions and then it’ll move on the next thread and we
can kinda hand wave away most of
the threading issues that we are running into and from there we
actually allow malware to run
threaded and when you think about what a malware actually
wants, it just cares that
there’s threads running and that didn’t get an error with a
thread right? It just as long as
it got a successful return value out of create thread it just
assumes the thread is running
and is probably looking for information to be updated at
some point it doesn’t really
matter when. So that that’s where this this round robin
scheduler, really shined was
because it was something so simple but we were able to
actually get stuff to to run
through completely even though it was multithreaded and here’s
here’s a quick example of of
that action,pay the most attention to the left side of
all those highlighted numbers so
in the numbers between the brackets are all thread IDs and
this is like a standard output
of Binee output function calls so as you can see as time goes
on that the threat ID will
change cause we’re context switching to a different thread
and then from there it’ll just
kinda continue forward until it completes all these threads are
really doing in the highlighted
lines are just creating threads in each each thread is at some
point printing something and you
can actually see some of the print F stuff with the format
strings right there we have a on
the first print F you can see the percent D etc. You can see
what’s going to be put into that
line when it’s actually written to console. So another thing
that we actually ran into when
we are running samples against Binee was we saw some to some
malware actually start dropping
files and in and and and this case that would cause us to
pursue DllMain stuff was it was
dropping DLLs to disk and then it was loading them up
dynamically and so we actually
weren’t doing anything with loading the DLLs dynamically up
until this point in fact we’re
just all are doing is just running a DLL, sorry, parsing a
DLL and then while we’re doing
the parsing of the PEs and then from there it would we just kind
of run it we weren’t actually
running the DllMain of those of those DLLs themselves I’m so we
actually went about trying to
run DllMain that something is required for us to actually do
the library properly and
probably for implementing more stuff in the TIB and the PEB in
some cases especially for some
system-level DLLs will actually populate some values for us for
the TIB and the PEB so we can
actually go through and have those run and then it’ll
populate most of those fields
for us which is which is great we don’t actually have to to
spend time with a fine tooth
comb time kind on through and adding more value to those and
that will probably drive us
crazy at some point, so what we end up doing actually tried two
ways of implementing DllMain, so
for any DLL that we are loading up statically when the, as if
we’re pretending to be the
loader what we were will originally try to do was just
set the stack with the arguments
that were required, set the entry point to to the start of
the DLL, DllMain if it did exist
if it didn’t we skip over it and then the return address from
that would actually point to
somewhere else in Binee’s memory where we had actually put
interrupts and so the interrupts
would pause emulation and then we would then go and update the
stack with the next DLL that
needed to be ran and then from there if if if it also had a
DllMain we just run through that
again and so on so forth but it turns out that when we were
actually pausing the DllMain we
are pausing the emulator it would actually cause it can be a
little bit more of an unclean
state for the emulator itself so we want to stick more to the
press the button once one array
to go loaded every thing at a time and go and when we
accomplish that is just through
a ROP chain essentially so the idea behind this is that we
wanted to set the stack in a way
in the way in a way such that when we actually started the
emulation of the first entry
point to be the first DLL that we needed to load, typically
this is an ntDll and then on
Kernal32 so we would set the stack with the arguments that we
need for that and then we do the
return address onto the stack but in this case the return
address for the for the first
DLL would be the entry point of the next DLL that needed to run
so we just kinda keep chaining
these together in the stack so that when we return in a DLL it
would then pop the address of
the next DLL into the instruction pointer and then
from there we can just go
through all the DLLs until her done and finally we the last
deal in line on the return
address for that will just be the entry point of the PE that
we’re testing against. This is
actually quite a great way to do it were able to hit the
emulation start button once and
then it was able to just continue through and then we are
actually getting some great
results a lot more fidelity especially since were having a
lot more set up of of them of
the mock OS done by the DLLs themselves which is great and
from there we can actually then
take the same idea and apply to say load library with a full
hook we could then just
obviously give a few different arguments argument values and
then from there we can do more
than that so so I think that’s about it. Now we have some
demos. So the first like half of
these demos kinda go through some of the like how you run
this at scale or how it would
look at scale but the and then will so shome so show some real
malware and I’ll try to pause
it.. so in the beginning is just the others a bunch of feeder, a
bunch of the parameters probably
the most notable ones are just the –V the and VV Oh yeah,so
first one is a yeah our API sets
I guess we thought that’s cool so we added it in there it was
super helpful for when you’re
doing, when you’re building this is you have to be able to
resolve those quickly but there
is a verbose mode so when you’re doing verbose mode like I said
earlier you get the instructions
which is like super helpful for R-ing things but then if you do
–VV you also get the registers
in the stack or at least a subset of the stack and then
another flag which is like – D
so you’ll get the the actual DLL that it’s in.. DLL: the function
in the name.. so just going
through here this is a very simple kind of a printf example
basically of a console
application and we actually start at the beginning of the
entry point and go all the way
through and were getting your nice you know, detailed
information about the function
parameters this pretty cool or getting human readable stuff
from like like printf you know
create file, write file you’re getting really good data here.
So now we’re just showing some
of the verbose mode.. and again so when you’re doing REing of a
piece of malware like having our
say the instructions is really helpful especially when you’re
trying to manipulate the config
file to maybe take a different branch you can kinda just go
through here and see what’s
actually happening after the function call change modify the
configuration file which changes
the environment and now the binary runs completely
differently.. and then the – VV
sort of the same thing except as I mention you now get the
registers and then a dump of the
stack as well so useful but I’m not as useful as is the other
one but this is interesting
information nonetheless when you’re particularly debugging by
hand. So now to the last of the…
the – D, you already know the actual API set was this where we
this is the reason we actually
implemented the API set the ‘– a’ and ‘A’ within Binee that is
because were getting a lot of
this and we know are I would API set is that, okay what DLL is
that, I was the function we need
to look at see if it’s a full hook or partial hook or
something like that.. And again
just kind of looking at the data, create file write file
your getting all these IOCs are
seeing what the malware is doing without actually executing. So
this is the key piece or use of
the –J flag right it converts all this to JSON so we put this
in our cluster we get all of our
samples this is what we’re getting back so then we go
through and we can parse these
for all the different interesting functions that we’re
looking for so in this case are
looking at write file and we get the interesting part here is we
get the parameters right, the
string value of the parameters you also get the values is being
passed to it so you’ll know
exactly what’s happening, so you know this function is slightly
less interesting but the malware
thats coming next is a little more interesting. But again you
can parse all the data in
real-time and we can do this you can do this in scale, this will
run, run on Linux, in Docker
It’ll also run in whatever function as a service is for
your cloud provider. so
threading is this is this is actually some sort of simple to
implement but is really cool and
actually got it to work. It’s just one of those ah-ha moments.
So now for some real malware. So
this first case is from from the I believe it’s from the orange
worm variant, one of their
samples and the others would run all the way through and this is
part of that family I think
there is maybe thirty samples in that family an interesting thing
here is, we get the we get the
IOC we know what service is actually trying to start, we can
do this without actually even
running the sample. So now we know where to look at for
hunting you in your environment
you’re looking for particular server you’re looking for
particular malware and now you
can see some of these IOCs so now you can hunt in your
environment and figure out where
these things actually are additionally there’s the skip
rock address so this is useful
for getting around some obfuscation and some packers you
know if they hide all the you
know from the import still enough to get that statically
but you can get that now
dynamically and this is a pretty useful feature for any of your
statistics. So this next one
this is an interesting sample because basically has multiple
layers of packing and then
unpacking what it does is effectively, well, so this is
particularly interesting cause
now we’re getting this is hidden previously by all of the.. from
the static analysis cause it was
in the import table directly getting this data in real-time
so we can add these to our
machine learing model say this thing actually does use these
imports, these are the
functions, these are the names, this is the DLL. And then
additionally you can see right
below it we’re getting registry values, getting registry keys
but what’s interesting about the
samples you it’s completely packed and were also does is it
unpacks a DLL and memory and
then it writes it to disk packed and then it loads itself and
then and then unpacks again and
that’s kind of this part where it’s.. you read files so now
we’re getting all this we
actually get the DLL that it’s that dumping, you get the file
name, the naming scheme a little
bit and then you again you see the load libraries we could get
ROC address you’re getting all
of these IOCs adding, tagging this binary in our ingestion
pipeline with all of these these
new IOCs, and then we’ll actually be able to collect new
ones and now we have a new DLL,
this thing was written to disk but it is written and is
redirected into a temp loacation
or sandbox location and now we can look at it later. We’re Open
Sourcing it, sorry, clearly we
had a couple things we want to work on next, but yeah, we are
are open sourcing it so we’re
more than happy to help anyone get involved and get started but
so these are some of the things.
So, thank you

Leave a Reply

Your email address will not be published. Required fields are marked *