In Depth Malware Analysis
De-obfuscating Malicious JavaScript
First beautify the
js
JavaScript can de-obfuscate its portions during runtime, then supply the resulting scripts to function
eval
to execute themBrowser Specific JS can also use statements such as
Always search for
eval
firstExecute the script so it de-obfuscates itself as you observe it
Use standalone script interpreters
SpiderMonkey
on REMnux andCScript
on WindowsIf you are decoding a browser script, you'll need to remove non-js (HTML) components
You'll need to intercept functions like
eval
and define the missing objects that would have been supplied by the OS or the app
REMnux includes some definitions in
/usr/share/remnux/objects.js
Specify it as the first
-f
parameter inSpiderMonkey
Use this as a starting point
Modify it based on the needs of the specimen
Tweak a copy of the file so you don't break the original
Supply
objects.js
as the first parameter to de-obfuscateloveyou.js
js -f /usr/share/remnux/objects.js -f loveyou.js > loveyou-out.js
more loveyou-out.js
Alternative
Run the script on Windows using CScript to monitor its activities via AMSI
Alternative 2
Add the new definition to the type of
loveyou.js
Use
WScript.Echo
inCScript
instead ofprint
inSpiderMonkey
If you just want to see the de-obfuscated script without executing it, delete the lines that contain
origional_eval
Now add this code to the top of the malicious script using
Notepad++
then save
Another Example
Use
SpiderMonkey
to de-obfuscatefgg.js
Take not the error is
location is not definied
When you open the script you see
location.href
Could that be the de-obfuscation key?
When saving suspicious web pages capture the URLs and headers in case de-obsfucation needs them
in
fgg.js
the URL used as a call out was `http://gitporg.com/cgi-bin/index.cgi?fggTo de-obfuscate
fgg.js
copy objects.js and then adjustlocation.href
to specify the expected valueAdjust This:
Supply the edited file when executing
fgg.js
inSpiderMonkey
then examine the outputThe de-obfuscated script reveals a URL that we couldn't see in the original script
Additional Considerations for de-obfuscating JS
Be carful modifying brower scripts if they call
arguments.callee
because this allows the function to examine its own bodyExample:
var M1FDAB=arguments.callee.toString()
You can use the debuggers built into web browsers to de-obfuscate browser scripts as they run
For JS designed to run outside the browser try
box-js
If you encounter scripts for PDF files extract them then de-obfuscate them with
SpiderMonkey
Recognizing Packed Malware
Malware authors can protect their creations by packing them
Packers are tools that compress, obfuscate, encrypt, or otherwise encode the original code
the packed program decodes the code into memory when it runs
This safeguards the specimen form static analysis techniques
Packed programs are also difficult to disassemble and or debug
Not all malware is packed
The unpacking code extracts the original program to memory and runs the program from memory
Packers conceal the original code and can hide some PE header values to further complicate analysis
Sections: Regions of code or data the comprise the executable file which will be loaded into memory
The entry point: Address of the first instruction in the program (officially called
AddressOfEntryPoint
)Import Address Table IAT: Pointers to function in external DLLs (That is API calls)
Packers differ in techniques, sophistication, and the protection they provide
Types of Packers
We will start with
UPX
which is free and common, simple to unpackIt has built in unpacking capabilities
However it can be scrambled to complicate unpacking
Numerous other packers exist, they tend to be more complex than UPX
Other packers:
Most packers do not include built in unpacking capabilities
Basic Unpacking
If possible try to identify the packer, research it and look for unpacking tips
You can tell that the executable might be packed if:
Static property tools can assist us to include:
Bytehist
generates byte usage histograms to spot packed filesNot packed: Less uniform distribution of byte values
Packed: More uniform distribution of byte values
Detect It Easy
andExeinfo
PE try to identify packer names
Determining whether the specimen is packed and identifying the packers are among the first steps in examining malware
Getting Started with Unpacking
UPX can usually auto unpack the sample
We can try other tools if UPX fails such as
Ether
andUnpacMe
The unpacking scripts for x64db can be helpful sometimes
Disable ASLR
Before trying to unpack the specimen disable ASLR
The PE header includes the
ImageBase
field. This is the virtual address where the executable wants to be loaded into memoryWith ASLR Windows ignores
ImageBase
, randomizing the base address to make it harder to exploit the processThis complicates unpacking and other code analysis techniques
Designate the packed executable incompatible with ASLR
You can disable ASLR on a per file basis
Find the
DllCharacteristics
field in the PE header withinCFF Explorer
Disable the
DynamicBase
Flag in it (DLL Can Move
)Save off the modification to the file to create a new file
An alternative is to use the command
setdllcharacteristics -d
Viewing the unpacked strings
Execute the packed specimen allowing it to unpack itself into memory so that you can extract its unprotected strings
Look at the strings via
Process Hacker
via Properties --> Memory --> Strings --> OkAlternative: Dump the unpacked process from memory
Several tools can extract the unpacked program from memory and save it to the file system
We need to tweak the PE header of the resulting file so that we can analyze it more easily
`Rebuild in the Import Address Table (IAT)
Be mindful of the Original Entry Point (OEP)
We will use Scylla for this, other relevant tools include PE Tools and Imports Fixer
Attach to the process using Scylla then dump the process
Use the X64 version of Scylla since we are extracting a 64 bit program
Select
brbbot.exe
process then click dump and save to a fileFind the IAT in the packed process and add it to the dumped file
We could perform static analysis on the dumped file, however it will not run, probably because of the entry point field
The unpacked code is probably in
NPX0
which is no longer emptyThe other sections that probably contain the unpacking code and the packed program are still present
We did not adjust the entrypoint
Dumping the process offers a fast way of unpacking the sample
Allow the malicious program to unpack itself then dump it
This approach is fast and doesn't require a lot of precision
The resulting file contains decoded strings and code and is well suited for static analysis
However in many cases the file wont be runnable due to the incorrect entry point value and other PE header issues
Using Debuggers for Dumping
Using a debugger for a more controlled approach to unpacking
Load the packed sample into a debugger (x64db)
Locate the end of the un-packer and set a breakpoint there
Note: This process can be time consuming and challenging with some packers
Run the specimen to let it unpack the original program into memory and pause at the end of the unpacker
Single step to let the process jump to the unpacked code (OEP)
Note: Most times it will be a
jmp
right before a lot ofadd byte ptr ds:[ax/rax], al
instructionsDump the unpacked process at that time (
OllyDumpEx
)Fix up the PE header paying attention to the IAT and EP
Set a breakpoint (F2) at the end of the unpacker then run the specimen (F9) to reach it
Once paused at the breakpoint single step (F7 or F8) to jump to the beginning of the unpacked code and pause again
Note: F7 and F8 are the same unless the instruction is a call in which case you can execute this function in one step (F8, step over) or single step through each of its instructions (F7, step into)
Confirm that you're looking at unpacked code by searching this region for the referenced strings and intermodular calls (right click, search for, current region, string references)
Use
OllyDumpEx
to dump the process after jumping to theOEP
Press
Get RIP as OEP
to set the entry point of the new file so it matches the address of the instruction where you're pausedDouble click section
UPX1
and addMEM_WRITE
to its flags to preempt an access violation when running the dumped fileActivate
x64dbg
'sScylla
plugin to fix theIAT
in the dumped fileOverview
Dumping the process from within a debugger offers a powerful way of bypassing packers in a controlled manner
Exit the
Scylla
plugin andx64db
. Run the dumped and fixed file to confirm that it works
Debugging Packed Malware
We can debug malware without dumping its unpacked code
Sometimes dumping unpacked malware from memory can be too time consuming or impractical
Even if you dump the process you might not be able to get the file to run due to OEP, IAT, or other problems
It is useful to know how to use a debugger to navigate through the process that began its life as a packed program without dumping it
Run the packed specimen in the debugger allowing it to unpack itself without worrying about finding the end of the unpacker
Without dumping we need to locate the unpacked code in x64db
We could preemptively set breakpoints on API calls that we know unpacked code will make, for example:
SetBPX ReadFile
From the memory map we can find the section where the executable code for the sample is mostly likely located, click on that segment, and follow in disassembler
Note this is only possible if you run the sample prior and it doesn't auto quit
You can now examine code that was unpacked into
NPX0
for instance by extracting intermodular API callsYou can search for the resulting references for interesting API calls and then examine their context in the CPU's disassembler tab
Once you search for intermodular calls right click on the interesting ones and select
Follow in Disassembler
Once you are back in the disassembler and can see the call you want set a hardware breakpoint on the call so you can spy on the results
Restart the program and then run it to hit the BP and confirm that you decoded the file
Last updated