Malware Analysis using Radare2
by Divya
Breaking down infections for fun. Exploring r2 while breaking down the first ever discovered malware for Apple M1 chips.
Brief intro
Malware has been a predominant threat to computers, networks, and infrastructures for decades now. Detecting these pieces of nuisances has been an ordeal as malware analysts are coming about with new and improvised ways to detect and nip them in the bud before they create destruction.
Discovering newly designed ones in the Wild
Detecting previously attacked malware can be easy based on signature or anomaly. Storing their signature in databases, developing rules based on typical behaviours of such malicious code has been proved efficient thus far.
What about the newer ones?
Noticing weird behaviour in your system? Get the app, we are going to do some reversing today.
I will be using the newest and the first malware discovered in the wild for Apple M1 Chips :) Details about the malware can be found here (Thanks to virustotal!): GoSearch22
As you can now see GoSearch is an “adware”, meaning it is capable of hijacking the settings of the mac device and
causes automatic redirection to specific webpages. Works for all major browsers(Like Safari, Firefox, Chrome).
Watch carefully the /details section to get a quick view of what it is (more revealed to you in this blog)
For the more curious ones, feel free to continue to the graph feature where you will get a better representation
of the calls made by the file.
First things first. Verify what type of file do we have here:
┬─[divya at racharch in ~/a/b/r/mldt]
╰──> λ file sample
sample: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>] [arm64:Mach-O 64-bit arm64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>]
[Note: If you were curious about what universal binaries are: We can be friends!]
We have our sample. Let’s start exploring
- Let’s unpack it on radare2. Fire up r2, let’s start with the simplest syntax with no flags:
┬─[divya at racharch in ~/a/b/r/mldt]
╰──> λ r2 sample
-- what happens in #radare, stays in #radare
[0x100001d20]>
- Before we begin,
?
command: to get a brief description of what a command can do use the command followed with a ?. Like:
[0x100001d20]> ?
Usage: [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ...
Append '?' to any char command to get detailed help
Prefix with number to repeat command N times (f.ex: 3x)
| %var=value alias for 'env' command
| *[?] off[=[0x]value] pointer read/write data/values (see ?v, wx, wv)
| (macro arg0 arg1) manage scripting macros
| .[?] [-|(m)|f|!sh|cmd] Define macro or load r2, cparse or rlang file
Truncated
- Before we start viewing different areas, we need to make sure r2 has finished analyzing the whole binary. You can also interpret this as r2 should know what is where. We run the aa command twice.
[Note: Again, if ever in doubt on the command, go ahead and see what
aa?
says about it.]
[0x100001d20]>aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Parsing metadata in ObjC to find hidden xrefs
[x] Found 0 objc xrefs in 122 dwords.
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
[0x100001d20]> #done!
[Note: This might not be a thorough tutorial of r2, I will be walking through the useful ones. You can always find more on r2book]
- Now that our binary is analyzed, let’s find out more info on our binary. We do it with the info command
i
:
[0x100001d20]> iI?
| iI Binary info
[0x100001d20]> iI
arch x86
baddr 0x100000000
binsz 414368
bintype mach0
bits 64
canary true
Truncated
We are done with our first scan on GoSearch using r2!
- Now that we have the info, we can look in the insides. Let’s list all the analyzed functions inside the binary.
[0x100001d20]> afl?
Usage: afl List all functions
| afl list functions
| afl. display function in current offset (see afi.)
| afl+ display sum all function sizes
[0x100001d20]> afl
0x100001d20 90 4333 entry0
0x100053410 1 6 sym.imp.CC_MD5
0x100053416 1 6 sym.imp.CGEventSourceSecondsSinceLastEventType
Truncated
- Like every executable, a malware has ways of importing data and exporting them to other places.
Should we want to see those, we use
i
again.
We see the exports using e
(for entrypoints) and E
(for exports).
[0x100001d20]> iE?
| iE Exports (global symbols)
| iE. Current export
[0x100001d20]> ie?
| ie Entrypoint
| iee Show Entry and Exit (preinit, init and fini)
[0x100001d20]> ieE
[Entrypoints]
vaddr=0x100001d20 paddr=0x00002d20 haddr=0x000009b8 type=program
1 entrypoints
[Exports]
nth paddr vaddr bind type size lib name
―――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00001000 0x100000000 GLOBAL FUNC 0 __mh_execute_header
For viewing imports or API calls to different locations of the system, we use i
.
[0x100001d20]> ii?
| ii Imports
[0x100001d20]> ii
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――――――――――――――――――
0 0x100053410 NONE FUNC CC_MD5
1 0x100053416 NONE FUNC CGEventSourceSecondsSinceLastEventType
Truncated
Demo 1
- Travel to a different region, let’s change the seek!
There are several things you can do with r2. As we are done with a basic info gathering around our sample. We can now
try walking around different areas and see in detail what a section of the code looks like. Seek command or s
is made
exactly for this. Viewing at the different API calls we select one and move to the section where it is actually
imported.
[0x100001d20]> s?
Usage: s # Help for the seek commands. See ?$? to see all variables
| s Print current address
| s.hexoff Seek honoring a base from core->offset
| s:pad Print current address with N padded zeros (defaults to 8)
| s addr Seek to address
[0x100001d20]> ii~IOServiceMatching
6 0x100053434 NONE FUNC IOServiceMatching
[0x100001d20]> s 0x100053434
[0x100053434]> #seek address changed!
Notice the change in the seek pointer? Now we are at the point of the code where the IOServiceMatching API is geting called. How do we know? It is dissassembly time!
[0x100053434]> pd?
Usage: p[dD][ajbrfils] [len] # Print Disassembly
| NOTE: len parameter can be negative
| NOTE: Pressing ENTER on empty command will repeat last print command in next page
| pD N disassemble N bytes
| pd -N disassemble N instructions backward
| pd N disassemble N instructions
| pd--[n] context disassembly of N instructions
Truncated
Demo 2
- Viewing more in GUIstic way
At this point, you are now capable to explore different areas of a binary, watch function calls/print statements, stare
at funny looking symbols like rax, rsi, rbi,etc (if you do not find them funny, there’s something for you in the next
section.) Radare2 offers a visual mode with v
command. With different commands viewed on each panel, analyzing becomes
easier. It supports navigating with both mouse and keyboard. Cool isn’t it?
Visual Panel Mode:
Hit <Shift>+<">
keys to see what more you can see other than the default. If you are interested in reading x86, I strongly recommend you to go through options of viewing Registers, RegRefs, Disassembly summary.
- Viewing calls and refs through graphs
Yet another feature of r2 is viewing whole binary in form of a graph with all functions calls chalked out in asciiart.
Hit VV
to enter graphical mode. Each node is labeled with a series of [a-z], simply type the sequence to select and
view that node.
Digging into the binary, r2 commandlinefu
- Grepping out specific sequence of strings of interest.
Now since we know how to browse around and have a basic idea of what we expect, we start scraping out any potential
strings inside the binary. We use
i
but this time with the flagz
for strings:
[0x198e3e6e3]> iz?
| iz|izj Strings in data sections (in JSON/Base64)
| izz Search for Strings in the whole binary
| izzz Dump Strings from whole binary to r2 shell (for huge files)
| iz- [addr] Purge string via bin.str.purge
[0x198e3e6e3]> iz
[Strings]
nth paddr vaddr len size section type string
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x0005379e 0x10005379e 7 10 3.__TEXT.__const utf8 ZQ6J\bԳߛ blocks=Basic Latin,Armenian,NKo
1 0x000537fc 0x1000537fc 4 6 3.__TEXT.__const utf8 ]tܪ\n blocks=Basic Latin,Syriac
2 0x000538b2 0x1000538b2 4 5 3.__TEXT.__const ascii 1lAW
3 0x000538d2 0x1000538d2 6 7 3.__TEXT.__const ascii |\rSIy
4 0x000538f6 0x1000538f6 4 7 3.__TEXT.__const utf8 '顇(Z blocks=Basic Latin,CJK Unified Ideographs
5 0x000539d2 0x1000539d2 4 5 3.__TEXT.__const ascii 3y{m
6 0x00053a0c 0x100053a0c 5 7 3.__TEXT.__const utf8 |` ;ݲ blocks=Basic Latin,Arabic Supplement
7 0x00053a5a 0x100053a5a 4 5 3.__TEXT.__const ascii [wMm
8 0x00053a7d 0x100053a7d 4 5 3.__TEXT.__const ascii ]i6j
9 0x00053ab0 0x100053ab0 4 5 3.__TEXT.__const ascii jjQ$
Use ~<string>
with iz
to search for specific areas where the string is present. Now since we are analyzing a MacOS
application (and me being too poor to posses a Mac), shouldn’t we have a basic idea of the file hierarchy?
Ladies and Gentlemen, this is when Google autosuggestions saves your hardwork of browsing articles
There’s lot to find out using the iz
command:
- Grepping down Method names of interest
[0x100001d20]> iz~application
92 0x00055dd8 0x100055dd8 27 28 4.__TEXT.__objc_methname ascii applicationShouldTerminate:
93 0x00055df4 0x100055df4 21 22 4.__TEXT.__objc_methname ascii application:openURLs:
94 0x00055e0a 0x100055e0a 21 22 4.__TEXT.__objc_methname ascii application:openFile:
95 0x00055e20 0x100055e20 22 23 4.__TEXT.__objc_methname ascii application:openFiles:
96 0x00055e37 0x100055e37 25 26 4.__TEXT.__objc_methname ascii application:openTempFile:
97 0x00055e51 0x100055e51 34 35 4.__TEXT.__objc_methname ascii applicationShouldOpenUntitledFile:
98 0x00055e74 0x100055e74 28 29 4.__TEXT.__objc_methname ascii applicationOpenUntitledFile:
99 0x00055e91 0x100055e91 30 31 4.__TEXT.__objc_methname ascii application:openFileWithoutUI:
- Grepping down Urls visited
[0x100001d20]> izz~http
3253 0x00060f43 0x100060f43 30 31 ascii http://crl.apple.com/root.crl0
3272 0x0006135d 0x10006135d 31 32 ascii https://www.apple.com/appleca/0
3296 0x00061828 0x100061828 38 39 ascii $http://ocsp.apple.com/ocsp03-devid060
3298 0x00061943 0x100061943 44 45 ascii *http://www.apple.com/certificateauthority/0
3311 0x00061c63 0x100061c63 280 281 ascii <?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE
plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist
version="1.0">\n<dict>\n\t<key>cdhashes</key>\n\t<array>\n\t\t<data>\n\t\t8eww0u7pc24HrxN+85hMK8UnB3g=\n\t\t</data>\n\t</array>\n</dict>\n</plist>\n0\r
3334 0x000621e2 0x1000621e2 29 30 ascii http://www.apple.com/appleca0
3337 0x000622ee 0x1000622ee 36 37 ascii "http://crl.apple.com/timestamp.crl0
3363 0x0006270c 0x10006270c 30 31 ascii http://crl.apple.com/root.crl0
3381 0x00062b26 0x100062b26 31 32 ascii https://www.apple.com/appleca/0
I kept the best for the last.
Now as we may all love command line (probable reason why you are reading about r2 and not IDA), but hold your horses, r2 has a web interface too! And you do not need cutter for that!
- Access web interface
Use =?
to find out what more instances can r2 connect to
[0x100001d20]> =?
Usage: =[:!+-=ghH] [...] # connect with other instances of r2
remote commands:
| = list all open connections
| =<[fd] cmd send output of local command to remote fd
| =[fd] cmd exec cmd at remote 'fd' (last open is default one)
| =! cmd run command via r_io_system
| =+ [proto://]host:port connect to remote host:port (*rap://, raps://, tcp://, udp://, http://)
| =-[fd] remove all hosts or host 'fd'
| ==[fd] open remote session with host 'fd', 'q' to quit
| =!= disable remote cmd mode
A basic http web interface can be stirred up using =H
flag
┬─[divya at racharch in ~/a/b/r/mldt]
╰──> λ r2 -AA -c =H sample
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Parsing metadata in ObjC to find hidden xrefs
[x] Found 0 objc xrefs in 122 dwords.
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
Starting http server...
open http://localhost:9090/
r2 -C http://localhost:9090/cmd/
R2 Web interface. Check these out!
Binary Info from
iI
Debugger(I will cover it sometime later)
Ending Note
As said earlier, covering the glory of this open source reversing tool in just one article will be too shameful. If you are interested in reversing and want to know more about r2, I will drop down various source links. That includes macOs file system info and many more! If you find any errors in this article, make sure to contact me(See bottom of page).
[Sources]