Skip to content
This repository was archived by the owner on Feb 12, 2026. It is now read-only.

Commit 9cf8e30

Browse files
authored
add: Android 10 support to dex2oat hardening (#17)
This commit adds support to Android 10 and lower versions that utilize XML instead of ABX for "packages.xml" file by utilizing a XML parser to perform if detected to not be ABX.
1 parent c04afe8 commit 9cf8e30

File tree

4 files changed

+2690
-20
lines changed

4 files changed

+2690
-20
lines changed

daemon/src/main/jni/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ set(SOURCES
99
logcat.cpp
1010
obfuscation.cpp
1111
packagename.cpp
12-
)
12+
)
1313

1414
add_library(${PROJECT_NAME} SHARED ${SOURCES})
1515

16-
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
16+
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${EXTERNAL_ROOT}/rapidxml)
1717

1818
target_link_libraries(${PROJECT_NAME} PRIVATE lsplant_static dex_builder_static android log)
1919

daemon/src/main/jni/abx_utils/abx_decoder.hpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,20 @@
1515

1616
class AbxDecoder {
1717
public:
18-
AbxDecoder(std::vector<char> str) {
18+
AbxDecoder(std::vector<char>* str) {
1919
mInput = str;
2020
}
2121

22+
bool isAbx() {
23+
// maybe empty?
24+
if (mInput->size() < 5) return false;
25+
26+
curPos = 0;
27+
std::vector<char> headerV = readFromCurPos(4);
28+
const char* header = reinterpret_cast<const char*>(headerV.data());
29+
return memcmp(header, startMagic, 4) == 0;
30+
}
31+
2232
bool parse() {
2333
if (!isAbx())
2434
return false;
@@ -142,29 +152,19 @@ class AbxDecoder {
142152

143153
private:
144154
int curPos = 0;
145-
std::vector<char> mInput;
155+
std::vector<char>* mInput;
146156
std::vector<std::vector<char>> internedStrings;
147157
std::vector<std::shared_ptr<XMLElement>> elementStack;
148158
bool docOpen = false, rootClosed = false;
149159
const std::vector<char> emptyString;
150160

151161
std::vector<char> readFromCurPos(int len) {
152162
// std::cout << "Reading " << len << " bytes of data from " << curPos << std::endl;
153-
std::vector ret(mInput.begin() + curPos, mInput.begin() + curPos + len);
163+
std::vector ret(mInput->begin() + curPos, mInput->begin() + curPos + len);
154164
curPos += len;
155165
return ret;
156166
}
157167

158-
bool isAbx() {
159-
// maybe empty?
160-
if (mInput.size() < 5) return false;
161-
162-
curPos = 0;
163-
std::vector<char> headerV = readFromCurPos(4);
164-
const char* header = reinterpret_cast<const char*>(headerV.data());
165-
return memcmp(header, startMagic, 4) == 0;
166-
}
167-
168168
char readByte() {
169169
return readFromCurPos(1)[0];
170170
}

daemon/src/main/jni/packagename.cpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,17 @@
1212
#include <errno.h>
1313
#include <stdbool.h>
1414

15+
#include <rapidxml.hpp>
16+
1517
static const std::string packages_path = "/data/system/packages.xml";
1618
static std::vector<char> LoadFileToStdVector(std::string filename);
1719

18-
extern "C" bool get_pkg_from_classpath_arg(const char* classpath_dir, char* package_name, size_t package_name_buffer_size) {
20+
// !!! DO NOT REMOVE THIS FUNCTION UNLESS YOU ADDED IT IN RAPIDXML !!!
21+
void rapidxml::parse_error_handler(const char *what, void *where) {
22+
LOGE("rapidxml Parser error: %s, Start of string: %s\n", what, (char *) where);
23+
}
24+
25+
extern "C" bool get_pkg_from_classpath_arg(const char* classpath_dir, char* package_name, size_t package_name_buffer_size) {
1926
size_t dir_len = strlen(classpath_dir);
2027
if(dir_len == 0 || dir_len >= 1024) {
2128
LOGE("Invalid classpath dir length: %zu", dir_len);
@@ -24,13 +31,60 @@ extern "C" bool get_pkg_from_classpath_arg(const char* classpath_dir, char* pack
2431

2532
std::vector<char> packagesFile = LoadFileToStdVector(packages_path);
2633

27-
if(packagesFile.size() < 1)
28-
{
34+
if(packagesFile.empty()) {
2935
LOGE("Failed to read packages.xml: %s", strerror(errno));
3036
return false;
3137
}
32-
33-
AbxDecoder decoder(packagesFile);
38+
39+
AbxDecoder decoder(&packagesFile);
40+
if (!decoder.isAbx()) {
41+
LOGD("This file is not ABX encoded, trying with XML fallback");
42+
43+
rapidxml::xml_document document;
44+
document.parse<0>(packagesFile.data());
45+
46+
rapidxml::xml_node<> *root_node = document.first_node();
47+
rapidxml::xml_node<> *current_node = nullptr;
48+
49+
if (strcmp(root_node->name(), "packages") != 0) {
50+
LOGE("The root tag is not packages!");
51+
52+
goto abort_xml_read;
53+
}
54+
55+
current_node = root_node->first_node("package");
56+
while (current_node) {
57+
{
58+
rapidxml::xml_attribute<> *name_attr = current_node->first_attribute("name");
59+
rapidxml::xml_attribute<> *code_path_attr = current_node->first_attribute("codePath");
60+
61+
if (!name_attr || !code_path_attr) goto continue_xml_loop;
62+
63+
char* code_path = code_path_attr->value();
64+
65+
if (strlen(code_path) != dir_len) goto continue_xml_loop;
66+
if (strncmp(code_path, classpath_dir, dir_len) != 0) goto continue_xml_loop;
67+
68+
char* name = name_attr->value();
69+
size_t name_len = strlen(name);
70+
71+
int copy_len = name_len < package_name_buffer_size - 1 ? static_cast<int>(name_len) : static_cast<int>(package_name_buffer_size - 1);
72+
memcpy(package_name, name, copy_len * sizeof(char));
73+
package_name[copy_len] = '\0';
74+
75+
document.clear();
76+
return true;
77+
}
78+
79+
continue_xml_loop:
80+
current_node = current_node->next_sibling("package");
81+
}
82+
83+
abort_xml_read:
84+
document.clear();
85+
return false;
86+
}
87+
3488
if (decoder.parse() && decoder.root.get() && strcmp(decoder.root->mTagName.data(), "packages") == 0) {
3589
for (auto pkg : decoder.root.get()->subElements) {
3690
if (strcmp(pkg.get()->mTagName.data(), "package") != 0) continue;

0 commit comments

Comments
 (0)