I have the .aab that I'm planning to upload on play store for publish, and before publishing I'm trying a decompile to see which data may be exposed to user in a reverse engineering process.
In .aab_FILES/base/ I see the assets.pb and resources.pb protobuffs - can these files be open some in some way? Cause for the moment I haven't found any method to reveal their content.
I am actually looking to see where are values/strings.xml packed - cause they are missing from .aab_FILES/base/res/ location and I wanna make sure my maps API key (which resides in strings.xml) won't be exposed to users.
The resources.pb is a serialization of the strings data, so they can't be directly extracted to xml.
There are 2 ways to go around this:
Convert from aab to apk
Use bundletool to convert the aab to a universal apk and read the xmls from there:
java -jar bundletool-all-1.8.0.jar build-apks --mode=universal --bundle=~/test.aab --output=~/universal.apks
The universal.apks file can now be unzipped. It contains a universal.apk file, which the resources can be taken from like any apk. The easiest way to get readable xml files from the apk is by using apktool:
apktool d ~/unzipped_universal_apks/universal.apk -o ~/unzipped_universal
The folder ~/unzipped_universal now contains the decoded universal.apk and the xml resources should be decoded and readable inside it.
Read the protobuf values directly from the protobuf file
In order to read a protobuf file, you need its scheme (or proto file).
The proto files for an aab are in the aapt2 repository:
Resources.proto which depends on Configuration.proto.
These files can be compiled to workable code in a number of programming languages. I'll show it using python as described here.
First though, the Resources.proto should be modified to import Configuration.proto from the same folder location instead of the original (unless you create the whole necessary folder structure).
So, change:
import "frameworks/base/tools/aapt2/Configuration.proto";
To:
import "Configuration.proto";
Now, in the terminal, run:
protoc --python_out=~/proto_output Configuration.proto Resources.proto
Inside ~/proto_output there will now be 2 files: Configuration_pb2.py Resources_pb2.py.
These files contain the python code to access the protobuf structure for the resources.pb file, as well as the protobuf encoded AndroidManifest.xml.
In order to read the protobuf file run:
from google.protobuf.json_format import MessageToDict
from Resources_pb2 import ResourceTable
res_obj = ResourceTable()
res_pb_file_path = '~/unzipped_app_bundle/base/resources.pb'
with open(res_pb_file_path, 'rb') as f:
content = f.read()
res_obj.ParseFromString(content)
# converting the protobuf object to a nice dictionary representation
res_dict = MessageToDict(res_obj)
Try this given de-compile jar BundleDecompiler
de-compile option:
java -jar BundleDecompiler.jar decompile --in=input_app.aab --out=output_dir
Related
Is it possible to get the config.xml file that is generated by Cordova based applications using Adroguard?
I cannot find it under the /res folder and it is not listed in the output of get_files() method.
apktool, on the other hand, is able to get the config.xml from the apk that is use it on.
Since it is under res folder, You need to get it by unzipping the file to a temporary directory and then parse it using Axml parser. In get_files(), you must see "resources.arsc" file. The res files are part of that. You can do something like :
config_xml_path = os.path.join(<your apk unzipped path>, 'res', 'xml', 'config.xml')
with io.open(config_xml_path, 'rb') as axml_file:
parsed_axml_file = AXMLPrinter(axml_file.read())
axml_content = parsed_axml_file.get_buff().decode('utf-8)
parsed_axml = minidom.parseString(axml_content.encode('utf-8'))
You might get some errors if the config.xml is badly formatted but I am not including the solution to handle those case. I hope you will get an idea with the above example.
How can I access a text file in my directory 'src/test/resources'
I can't seem to get it to pickup during my JUnit test
mobile/build.gradle:
sourceSets {
test {
java {
srcDirs = [ 'src/test/java' ]
}
resources {
srcDirs = [ 'src/test/resources' ]
}
}
}
Test method:
#Test
public void test_file() {
URL resource = getClass().getResource("file_four_lines.txt");
File file = new File(resource.getFile()); // Get NullPointerException here
...
}
Prefix the file path with /.
Basically, you'd do something like this:
File helloBleprintJson = new File(
getClass().getResource("/helloBlueprint.json").getPath());
Above snippet is taken from here.
I think this link will help. In your case why not hard code strings for testing? Why not use String.xml instead of "file_four_lines.txt". Internationalization requires a directory structure for each resource file having different language, screen size, orientation, flavor, night/day vision version. For this reason resources are compiled and accessed from the R file. You are trying to bypass this convention by using .txt instead of .xml and accessing the resource directly, it just feels wrong. I don't think testing is you problem as much as not following convention.
Forgive me for posting twice, I do have an answer from the official documentation" Arbitrary files to save in their raw form. To open these resources with a raw InputStream, call Resources.openRawResource() with the resource ID, which is R.raw.filename.
However, if you need access to original file names and file hierarchy, you might consider saving some resources in the assets/ directory (instead of res/raw/). Files in assets/ are not given a resource ID, so you can read them only using AssetManager." Json and txt are non-standard(unsupported) so you have to provide your own implementation/parcer to read this type file. Thanks for this post. I knew something about resources but thanks to your prodding now I know even more. To recap The Android resource system keeps track of all non-code assets associated with an application. The Android SDK tools compile your application's resources into the application binary at build time. To use a resource, you must install it correctly in the source tree (inside your project's res/ directory) and build your application. As part of the build process, the SDK tools generate symbols for each resource, which you can use in your application code to access the resources and of course the symbols referred to are in the generated R file
I have built FFmpeg for Android and want to use it in an application like so:
System.loadLibrary("avutil");
System.loadLibrary("swscale");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
The build output are lib*.so, lib*.so.MAJOR and lib*.so.MAJOR.MINOR.OTHER files. Inside the shared objects are references like lib*.so.MAJOR, for example libswscale.so.2 requires libavutil.so.52.
Now if I put the *.so files in the project's libs folder (more exactly libs/armeabi-v7a), I of course get
01-25 12:06:40.270: E/AndroidRuntime(2905): java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 107 could not load needed library 'libavutil.so.52' for 'libswscale.so' (load_library[1091]: Library 'libavutil.so.52' not found)
However if instead I put the *.so.MAJOR files in the libs folder to solve the linking exception, I get the same error when running the app from Eclipse. And I noticed the files do not even get exported if I create an APK! So how do I tell Eclipse to package the *.so.MAJOR files as libraries? Or alternatively, how do I compile the shared objects in a way that they reference each other by *.so instead of *.so.MAJOR?
EDIT: It seems there's no way to package *.so.XYZ files automatically.
Didn't find a solution to take the .so.MAJOR files as I wished. It seems to me that the Android build system only copies *.so files automatically and doesn't allow other file extensions.
So I rewrote the FFmpeg makefiles to have the shared objects reference each other by libXXX.so.
In library.mak, I replaced $(SHFLAGS) in the following recipe
$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SUBDIR)lib$(NAME).ver
$(SLIB_CREATE_DEF_CMD)
$$(LD) $(SHFLAGS) $(LDFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS)
$(SLIB_EXTRA_CMD)
so that the third line looks like
$(subst $$(#F),$(SLIBNAME),$(SHFLAGS))
For those who don't understand the substitution (like me before), check this directly related answer.
Actually, you don't need to do that.
What you need to do is edit the configure file.
And find out this:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
Modified them to be:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
Need to use a shared lib for android from 3rd party, the lib's soname and file name are same, in format libxx.so.1.2.3, which is common on linux. I rename the lib file to libxx.so, and link libxx.so in libmyjni.so using ndk-build. In my java code, before calling the functions in libmyjni.so, I load them like this:
System.load("/data/local/tmp/libxx.so.1.2.3");
System.loadLibrary("myjni");
I have to manually copy libxx.so.1.2.3 to /data/local/tmp/. It works well in this way, after above loading, I can call functions in libmyjni.so.
In code "System.loadLibrary("myjni");", system always trying to get libxx.so.1.2.3 from somewhere. I want to know, in the real world, how could I copy libxx.so.1.2.3 to a specific location on android device during installation? so that I can System.load() it.
Or android has official way to install self made lib to /system/lib/?
If libxx.so.1.2.3 is in format libxx.so then I can use System.loadLibrary("xx") to load it.
Here is finally what I did, keep the libxx.so.1.2.3 untouched and do all stuff in Java:
Put libxx.so.1.2.3 in android assets.
In MainApp.OnCreate(), copy the file to private file folder and load it from there:
AssetManager am = applicationContext.getAssets();
in = am.open(OPENSSL_SO_LIB_NAME); // source instream
File privateStorageDir = applicationContext.getFilesDir();
String libPath = privateStorageDir.getAbsolutePath(); // copy the lib to here ...
System.load(libPath + "/" + SO_LIB_NAME);
This is not a question about how to sign an .apk file. I want to know what does signing actually means and how it is implemented.
Inside the .apk file there is META-INF folder and inside that there are two files.
First one is CERT.SF contains SHA1 hashes for various components and looks like this:
Name: res/layout/main.xml
SHA1-Digest: Cox/T8fN1X9Hv4VqjH9YKqc/MsM=
Name: AndroidManifest.xml
SHA1-Digest: wZ418H9Aix1LNch3ci7c+cHyuZc=
Name: resources.arsc
SHA1-Digest: P+uoRrpFyVW6P3Wf+4vuR2ZSuXY=
Name: classes.dex
SHA1-Digest: cN3zXtGii9zuTOkBqDTLymeMZQI=
There is also a file called CERT.RSA. I assume it is the public key to verify the signature.
My question is, where is the signature for the whole .apk file is stored? And what is actually signed? It could be either
.apk file used as a single binary object and this is signed
or CERT.SF is signed which contains individual hashes for different components
It would be also much better if you can point me to the documentation of the detailed signing and verification process.
Indeed this is not a specific Android question but a Java-in-general question however I post an answer anyway...
First of all: Only the XXX.SF file is signed; this means that all the files mentioned in the XXX.SF file are signed "indirectly" because XXX.SF contains their hashes. In fact all files not located in "Meta-Inf" should have hashes there! The whole .apk archive is not signed.
The XXX.SF file is more or less a copy of the MANIFEST.MF file. There is a line "SHA1-Digest-Manifest" which is the SHA-1 hash of "MANIFEST.MF" itself; the "SHA1-Digest" lines do not contain the hashes of the files but the hashes of the tree corresponding lines in the Manifest.MF file just like this:
SHA1("Name: filename"+CR+LF+"SHA1-Digest: "+SHA1(file_content)+CR+LF+CR+LF)
The file format of XXX.DSA/.RSA is the same as for an S/MIME email signature (for the content of XXX.SF) however the data is not base64 encoded and no header/trailer lines are used. "openssl smime -sign -outform DER" would create this format.
Multiple certificates can be used to sign a ZIP file. In this case multiple pairs of (XXX.SF/.RSA, YYY.SF/.RSA, ...) will exist.
This actually has nothing to do with Android. APK files are signed using jarsigner. Here is a link to the manpage.