I need to parse string resources at the project build stage.
Before the aapt2, I did it like this. Now with the advent of aapt2, resources are collected in the *.arsc.flat format. Disabling apt2 is not suitable as a permanent solution. How can I parse resources in this format?
The correct way to do this would be to parse the output APK and get the symbols from it.
However, it is a lot of work and if you just want a hacky quick-fix you can instead inspect the R.txt file that's output by the process<Variant>Resources task. It's basically a list of all the resources in the project, including all the strings. The format is a line per resource in the form of:
<java type> <resource type> <resource name> <resource ID>
So you need to find all the lines with:
int string some_string_name <ID>
Related
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
I have a project with following locale values directory:
values
values-en-rHK
values-en-rTH
values and values-en-rHK contains:
<string name="currency">$</string>
values-en-rTH contains:
<string name="currency">฿</string>
After the APK is compiled, it removed the currency key from the values-en-rHK directory. I have verified this by decompiling the APK and looking into the resources.
This causes the app to show ฿, even when the locale is en-HK. Also noticed that all the strings with same text as in values were removed from values-en-rHK in the compiled APK.
Your localized directories are not named correctly. They should follow the pattern specified here:
<resource type>-b+<language code>[+<country code>]
I'm not entirely sure what you were attempting, the following could possibly work:
values
values-b+en+HK
values-b+en+TH
Values that are identical in different localization versions may be removed when compiling the APK, since there is no point to have the same value in multiple resources.
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
How are the names that appear for a symbol generated in a shared library file? For example, when using elfread -Ws to read the symbols in the libutils.so file (android system utils library), I get several symbol names of the format:
_ZN7android10VectorImpl14insertVectorAtERKS0_j
etc. How do you decipher this symbol name?
That appears to be a mangled name, e.g., for C++, and you can make better sense of those using the -C option of nm:
-C
--demangle[=style]
Decode (demangle) low-level symbol names into user-level names. Besides removing any initial underscore prepended by the system, this makes C++ function names readable. Different compilers have different mangling styles. The optional demangling style argument can be used to choose an appropriate demangling style for your compiler. See c++filt, for more information on demangling.
When using nm on shared libraries, this option shows their symbols:
-D
--dynamic
Display the dynamic symbols rather than the normal symbols. This is only meaningful for dynamic objects, such as certain types of shared libraries.
I am using to DexGuard to process my android applications.
On DexGuard's Homepage they say it features: XML resource obfuscation
I already tested DexGuard and decompiled my output .apks with apktool.
The problem is ALL resource files are decompiled succesffully, so they have not been obfuscated apparently.
Now my question is, does DexGuard automatically obfuscate XML resources or do i have to activate it somehow in my dexguard-project.txt file?
Is it possible to obfuscate XML resources like strings.xml or am I misunderstanding this feature?
Why do you want to obfuscate strings.xml? is it because you have api keys or oauth secrets in there? If so, then better to move them to assets/config.properties file and load to a java.util.Properties object like this...
Properties appConfigProperties = new Properties();
appConfigProperties.load(context.getAssets().open("config.properties"))
String myApiKey = appConfigProperties.get("my_api_key");
(for brevity I've removed the exception handling)
Be sure to enable asset encryption in your DexGuard config file:
-encryptassetfiles assets/**
I received the following statement from DexGuard:
Resource XML files are obfuscated automatically in release builds,
although the differences may be subtle. You can compare the
differences with for instance aapt d xmltree application.apk
AndroidManifest.xml. We are working on more obfuscation of resources
for upcoming versions.
After executing the proposed command aapt d xmltree application.apk (where application.apk is a simple HelloWorld Application) i finally could see what DexGuard actually obfuscates in XML files:
Each attribute in an XML resource file is identified by a name, but often also by a numeric identifier.
In AndroidManifest.xml for example:
android:versionName(0x010102lc) = "1.0"
In the obfuscation step, DexGuard can remove the name of an attribute, but only if this attribute also has a numeric identifier.
After DexGuard obfuscation the above attribute will look like this:
:(0x010102lc) = "1.0"
As XML elements of strings.xml for instance only have a name and no numeric identifier, there won't be any differences in the decompiled XML file.