Authored by Roman Fiedler | Site unparalleled.eu

This is a tool that was developed to run as alternative “/init”. The program will make an Android phone show up as mass storage device during boot. The complete internal storage is available for reading including the partition table and all 42 partitions of the Android system.

/** This software is provided by the copyright owner "as is"
* and WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES, including,
* but not limited to, the implied warranties of merchantability
* and fitness for a particular purpose are disclaimed. In no
* event shall the copyright owner be liable for any direct,
* indirect, incidential, special, exemplary or consequential
* damages, including, but not limited to, procurement of substitute
* goods or services, loss of use, data or profits or business
* interruption, however caused and on any theory of liability,
* whether in contract, strict liability, or tort, including
* negligence or otherwise, arising in any way out of the use
* of this software, even if advised of the possibility of such
* damage.
*
* Copyright (c) 2021 Unparalleled IT Services e.U.
* https://unparalleled.eu/blog/2021/20210626-android-internal-storage-as-mass-storage/
*
* The permission to use, copy, modify, and distribute this
* software according to GNU Lesser General Public License (LGPL-3.0)
* is hereby granted, provided that the above copyright notice
* appears in all copies.
*
* This program demonstrates how to initialize the USB interface
* on Android using the "/sys/class/android_usb/android0" drivers.
*
* Compiling:
*
* /usr/bin/arm-linux-gnueabihf-gcc -march=armv7-a ExfiltrateAsMassStorage.c -static -o ExfiltrateAsMassStorage
*/

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>


/** Write a string to a given file.
* @return 0 on success.
*/
int writeString(char* targetFile, char* valueStr) {
int targetFd = open(targetFile, O_WRONLY|O_CREAT, 0666);
if (targetFd < 0) {
return 1;
}
int length = strlen(valueStr);
int result = write(targetFd, valueStr, length);
if (result != length) {
return 1;
}
close(targetFd);
return 0;
}


/** Flash the light briefly a given number of times.
*/
void doBlink(int num) {
for (int cnt = 0; cnt < num; cnt++) {
writeString("/sys/class/leds/white/brightness", "100");
usleep(100000);
writeString("/sys/class/leds/white/brightness", "0");
usleep(500000);
}
sleep(2);
}


/** Write a list of strings to target files.
* @param writeList the list containing pairs of target file
* name and value. A NULL target file name ends the list.
* return 0 on success.
*/
int writeStringList(char** writeList) {
int writeCount = 0;
while ((*writeList) && (!writeString(*writeList, *(writeList + 1)))) {
writeList += 2;
writeCount++;
}

// Blink as often as the number of the failed data element.
if (*writeList) {
doBlink(writeCount + 1);
return 1;
}
return 0;
}


/** Initialize the USB device descriptor string values. The values
* are usually ignored by drivers so they can be used to report
* up to 126 bytes of data for debugging purposes.
* @return 0 on success.
*/
int initUsbInfo(char* manufacturer, char* product, char* serial) {
char* writeList[] = {
"/sys/class/android_usb/android0/iManufacturer", manufacturer,
"/sys/class/android_usb/android0/iProduct", product,
"/sys/class/android_usb/android0/f_mass_storage/vendor", "ShortStr",
"/sys/class/android_usb/android0/f_mass_storage/product", product,
"/sys/class/android_usb/android0/iSerial", serial, NULL};
return (writeStringList(writeList));
}


int main(int argc, const char *argv[]) {
// Create the memory block device in case it did not exist yet.
mkdir("/dev", 0755);
mknod("/dev/mmcblk0", S_IFBLK|0666, 0xb300);

// Make sure "sysfs" is mounted.
mkdir("/sys", 0755);
if (mount("sysfs", "/sys", "sysfs", MS_NOATIME, NULL)) {
// No sense to indicate the failure via blink code as sys is
// not mounted yet. Just "kill" init.
return 1;
}

// Blink three to indicate that the code is really running.
doBlink(1);

if (writeString("/sys/class/android_usb/android0/f_rndis/wceis", "1")) {
doBlink(2);
goto mainError;
}

// Set the USB device descriptor strings.
if (initUsbInfo("Exfiltrate", "AProduct", "BSerial")) {
doBlink(3);
goto mainError;
}

char* usbMassStorageInitList[] = {
"/sys/class/android_usb/android0/enable", "0",
"/sys/class/android_usb/android0/idProduct", "0x05c6",
"/sys/class/android_usb/android0/idVendor", "0x9026",
"/sys/class/diag/diag/logging_mode", "internal",
"/sys/class/android_usb/android0/f_mass_storage/lun/file", "/dev/mmcblk0",
"/sys/class/android_usb/android0/functions", "mass_storage",
"/sys/class/android_usb/android0/enable", "1", NULL
};
if (writeStringList(usbMassStorageInitList)) {
goto mainError;
}

// Sleep forever to use the phone as mass storage device.
while (1) {
sleep(1);
}

mainError:
// Blink 10x before exit. When this program is run as "init",
// exit will trigger a reboot of the device.
doBlink(10);
return 1;
}