Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
botherder committed Aug 3, 2021
0 parents commit 18ab4c5
Show file tree
Hide file tree
Showing 20 changed files with 1,538 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
github: botherder
patreon: botherder
ko_fi: botherder
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

build/
assets/
bindata.go
401 changes: 401 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

76 changes: 76 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
BUILD_FOLDER = $(shell pwd)/build
ASSETS_FOLDER = $(shell pwd)/assets

FLAGS_DARWIN = GOOS=darwin
FLAGS_WINDOWS = GOOS=windows GOARCH=386 CC=i686-w64-mingw32-gcc CGO_ENABLED=1

PLATFORMTOOLS_URL = https://dl.google.com/android/repository/
PLATFORMTOOLS_WINDOWS = platform-tools-latest-windows.zip
PLATFORMTOOLS_DARWIN = platform-tools-latest-darwin.zip
PLATFORMTOOLS_LINUX = platform-tools-latest-linux.zip
PLATFORMTOOLS_FOLDER = /tmp/platform-tools

lint:
@echo "[lint] Running linter on codebase"
@golint ./...

deps:
@echo "[deps] Installing dependencies..."
go mod download
go get -u github.com/go-bindata/go-bindata/...
@echo "[deps] Dependencies installed."

windows: deps
@mkdir -p $(BUILD_FOLDER)
@mkdir -p $(ASSETS_FOLDER)

@if [ ! -f /tmp/$(PLATFORMTOOLS_WINDOWS) ]; then \
echo "Downloading Windows Android Platform Tools..."; \
wget $(PLATFORMTOOLS_URL)$(PLATFORMTOOLS_WINDOWS) -O /tmp/$(PLATFORMTOOLS_WINDOWS); \
fi

@rm -rf $(PLATFORMTOOLS_FOLDER)
@cd /tmp && unzip -u $(PLATFORMTOOLS_WINDOWS)
@cp $(PLATFORMTOOLS_FOLDER)/AdbWinApi.dll $(ASSETS_FOLDER)
@cp $(PLATFORMTOOLS_FOLDER)/AdbWinUsbApi.dll $(ASSETS_FOLDER)
@cp $(PLATFORMTOOLS_FOLDER)/adb.exe $(ASSETS_FOLDER)
@go-bindata -pkg adb -o adb/bindata.go -prefix $(ASSETS_FOLDER) $(ASSETS_FOLDER)

$(FLAGS_WINDOWS) go build --ldflags '-s -w -extldflags "-static"' -o $(BUILD_FOLDER)/snoopdroid2.exe ./cmd/

darwin: deps
@mkdir -p $(BUILD_FOLDER)
@mkdir -p $(ASSETS_FOLDER)

@if [ ! -f /tmp/$(PLATFORMTOOLS_DARWIN) ]; then \
echo "Downloading Darwin Android Platform Tools..."; \
wget $(PLATFORMTOOLS_URL)$(PLATFORMTOOLS_DARWIN) -O /tmp/$(PLATFORMTOOLS_DARWIN); \
fi

@rm -rf $(PLATFORMTOOLS_FOLDER)
@cd /tmp && unzip -u $(PLATFORMTOOLS_DARWIN)
@cp $(PLATFORMTOOLS_FOLDER)/adb $(ASSETS_FOLDER)
@go-bindata -pkg adb -o adb/bindata.go -prefix $(ASSETS_FOLDER) $(ASSETS_FOLDER)

$(FLAGS_DARWIN) go build --ldflags '-s -w' -o $(BUILD_FOLDER)/snoopdroid2-darwin ./cmd/

linux: deps
@mkdir -p $(BUILD_FOLDER)
@mkdir -p $(ASSETS_FOLDER)

@if [ ! -f /tmp/$(PLATFORMTOOLS_LINUX) ]; then \
echo "Downloading Linux Android Platform Tools..."; \
wget $(PLATFORMTOOLS_URL)$(PLATFORMTOOLS_LINUX) -O /tmp/$(PLATFORMTOOLS_LINUX); \
fi

@rm -rf $(PLATFORMTOOLS_FOLDER)
@cd /tmp && unzip -u $(PLATFORMTOOLS_LINUX)
@cp $(PLATFORMTOOLS_FOLDER)/adb $(ASSETS_FOLDER)
@go-bindata -pkg adb -o adb/bindata.go -prefix $(ASSETS_FOLDER) $(ASSETS_FOLDER)

@go build --ldflags '-s -w' -o $(BUILD_FOLDER)/snoopdroid2-linux ./cmd/

clean:
rm -rf $(ASSETS_FOLDER)
rm -rf $(BUILD_FOLDER)
rm -f ./*/bindata.go
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Snoopdroid 2

[![Go Report Card](https://goreportcard.com/badge/github.com/botherder/snoopdroid2)](https://goreportcard.com/report/github.com/botherder/snoopdroid2)

Snoopdroid 2 is a portable tool to simplify the acquisition of relevant forensic data from Android devices. It is the successor of [Snoopdroid](https://github.com/botherder/snoopdroid), re-written in Go and leveraging official adb binaries.

## Build

In order to build Snoopdroid 2 you will need Go 1.15+ installed. You will also need to install `make`. When ready you can clone the repository and run any of the following commands, depending on which platform you would like to run Snoopdroid 2 on:

make linux
make darwin
make windows

These commands will generate binaries in a *build/* folder.

## Use

Before launching Snoopdroid you need to have the target Android device connected to your computer via USB, and you will need to have enabled USB debugging. Please refer to the [official documentation](https://developer.android.com/studio/debug/dev-options#enable) on how to do this, but also be mindful that Android phones from different manufacturers might require different navigation steps than the defaults.

Once USB debugging is enabled, you can proceed launching Snoopdroid 2. It will first attempt to connect to the device over the USB bridge, which should result in the Android phone to prompt you to manually authorize the host keys. Make sure to authorize them, ideally permanently so that the prompt wouldn't appear again.

Now Snoopdroid 2 should be executing and creating an acquisition folder at the same path you have placed your Snoopdroid 2 binary. At some point in the execution, Snoopdroid 2 will prompt you some choices: these prompts will pause the acquisition until you provide a selection, so pay attention.

The following data can be extracted:

1. A list of all packages installed and related distribution files.
2. (Optional) Copy of all installed APKs or of only those not safelisted by Snoopdroid 2.
3. The output of the `dumpsys` shell command, providing diagnostic information about the device.
4. The output of the `getprop` shell command, providing build information and configuration parameters.
5. The output of the `ps` shell command, providing a list of all running processes.
6. (Optional) A backup of SMS and MMS messages.
80 changes: 80 additions & 0 deletions acquisition/acquisition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Snoopdroid 2
// Copyright (c) 2021 Claudio Guarnieri.
// Use of this software is governed by the MVT License 1.1 that can be found at
// https://license.mvt.re/1.1/

package acquisition

import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/botherder/snoopdroid2/adb"
"github.com/satori/go.uuid"
)

type Acquisition struct {
UUID string
ADB *adb.ADB
BasePath string
APKSPath string
Datetime time.Time
}

// New returns a new Acquisition instance.
func New() (*Acquisition, error) {
acq := Acquisition{}
uuidBytes := uuid.NewV4()
acq.UUID = uuidBytes.String()
acq.Datetime = time.Now().UTC()

err := acq.initADB()
if err != nil {
return nil, fmt.Errorf("Failed to initialize adb: %s", err)
}

err = acq.createFolder()
if err != nil {
return nil, fmt.Errorf("Failed to create acquisition folder: %s", err)
}

return &acq, nil
}

func (a *Acquisition) initADB() error {
var err error
a.ADB, err = adb.New()
if err != nil {
return fmt.Errorf("Failed to initialize adb: %s", err)
}

_, err = a.ADB.GetState()
if err != nil {
return fmt.Errorf("Unable to get adb state, are you sure a device is connected?")
}

return nil
}

func (a *Acquisition) createFolder() error {
cwd, err := os.Getwd()
if err != nil {
return err
}

a.BasePath = filepath.Join(cwd, a.UUID)
err = os.Mkdir(a.BasePath, 0755)
if err != nil {
return err
}

a.APKSPath = filepath.Join(a.BasePath, "apks")
err = os.Mkdir(a.APKSPath, 0755)
if err != nil {
return err
}

return nil
}
121 changes: 121 additions & 0 deletions acquisition/apks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Snoopdroid 2
// Copyright (c) 2021 Claudio Guarnieri.
// Use of this software is governed by the MVT License 1.1 that can be found at
// https://license.mvt.re/1.1/

package acquisition

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/botherder/go-savetime/hashes"
"github.com/botherder/go-savetime/slice"
"github.com/i582/cfmt"
"github.com/manifoldco/promptui"
)

const (
apkAll = "All"
apkNotKnown = "Only not known"
)

type File struct {
Path string `json:"path"`
LocalName string `json:"local_name"`
SHA256 string `json:"sha256"`
}

func (a *Acquisition) getPathToLocalCopy(packageName, filePath string) string {
fileName := ""
if strings.Contains(filePath, "==/") {
fileName = fmt.Sprintf("_%s", strings.Replace(strings.Split(filePath, "==/")[1], ".apk", "", 1))
}

localPath := filepath.Join(a.APKSPath, fmt.Sprintf("%s%s.apk", packageName, fileName))
counter := 0
for true {
if _, err := os.Stat(localPath); os.IsNotExist(err) {
break
}

counter++
localPath = filepath.Join(a.APKSPath, fmt.Sprintf("%s%s_%s.apk", packageName, fileName, counter))
}

return localPath
}

func (a *Acquisition) DownloadAPKs() error {
fmt.Println("Downloading copies of installed apps...")

packages, err := a.ADB.GetPackages()
if err != nil {
return fmt.Errorf("Unable to retrieve list of installed packages: %s", err)
}

cfmt.Printf("Found a total of {{%d}}::cyan|bold installed packages\n",
len(packages))

fmt.Println("Would you like to download all APKs or only those not known?")
promptAll := promptui.Select{
Label: "Download",
Items: []string{apkAll, apkNotKnown},
}
_, downloadOption, err := promptAll.Run()
if err != nil {
return fmt.Errorf("Failed to make selection for download option")
}

for i, p := range packages {
if downloadOption != apkAll && slice.Contains(packageFilter, p.Name) {
continue
}

cfmt.Printf("Found Android package: {{%s}}::cyan|bold\n", p.Name)

pFilePaths, err := a.ADB.GetPackagePaths(p.Name)
if err == nil {
for _, pFilePath := range pFilePaths {
localPath := a.getPathToLocalCopy(p.Name, pFilePath)

out, err := a.ADB.Pull(pFilePath, localPath)
if err != nil {
cfmt.Printf("{{ERROR:}}::red|bold Failed to download {{%s}}::cyan|underline: {{%s}}::italic\n",
pFilePath, out)

continue
}

cfmt.Printf("Downloaded {{%s}}::cyan|underline to {{%s}}::magenta|underline\n",
pFilePath, localPath)

sha256, _ := hashes.FileSHA256(localPath)
file := File{
Path: pFilePath,
LocalName: filepath.Base(localPath),
SHA256: sha256,
}

packages[i].Files = append(packages[i].Files, file)
}
}
}

packagesJSONPath := filepath.Join(a.BasePath, "packages.json")
packagesJSON, err := os.Create(packagesJSONPath)
if err != nil {
return fmt.Errorf("Unable to save list of installed packages to file: %s", err)
}
defer packagesJSON.Close()

buf, _ := json.MarshalIndent(packages, "", " ")

packagesJSON.WriteString(string(buf[:]))
packagesJSON.Sync()

return nil
}
Loading

0 comments on commit 18ab4c5

Please sign in to comment.