From 9f7a3db8bed801fed5762a97bc6a647b410ef1c9 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 11 May 2022 17:07:58 -0700 Subject: [PATCH] Move cert extraction to its own file --- native/jni/Android.mk | 1 + native/jni/su/cert.cpp | 136 +++++++++++++++++++++++++++++++++++++ native/jni/utils/files.cpp | 109 ++++------------------------- native/jni/utils/files.hpp | 2 - 4 files changed, 151 insertions(+), 97 deletions(-) create mode 100644 native/jni/su/cert.cpp diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 89fd80a85..ad4e05584 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -33,6 +33,7 @@ LOCAL_SRC_FILES := \ su/su.cpp \ su/connect.cpp \ su/pts.cpp \ + su/cert.cpp \ su/su_daemon.cpp \ zygisk/entry.cpp \ zygisk/main.cpp \ diff --git a/native/jni/su/cert.cpp b/native/jni/su/cert.cpp new file mode 100644 index 000000000..7c01db632 --- /dev/null +++ b/native/jni/su/cert.cpp @@ -0,0 +1,136 @@ +#include + +using namespace std; + +// Top-level block container +struct signing_block { + uint64_t len; + + struct id_value_pair { + uint64_t len; + struct /* v2_signature */ { + uint32_t id; + uint8_t value[0]; // size = (len - 4) + }; + } id_value_pair_sequence[0]; + + uint64_t block_len; // *MUST* be same as len + char magic[16]; // "APK Sig Block 42" +}; + +struct len_prefixed { + uint32_t len; +}; + +// Generic length prefixed raw data +struct len_prefixed_value : public len_prefixed { + uint8_t value[0]; +}; + +// V2 Signature Block +struct v2_signature { + uint32_t id; // 0x7109871a + uint32_t signer_sequence_len; + struct signer : public len_prefixed { + struct signed_data : public len_prefixed { + uint32_t digest_sequence_len; + struct : public len_prefixed { + uint32_t algorithm; + len_prefixed_value digest; + } digest_sequence[0]; + + uint32_t certificate_sequence_len; + len_prefixed_value certificate_sequence[0]; + + uint32_t attribute_sequence_len; + struct attribute : public len_prefixed { + uint32_t id; + uint8_t value[0]; // size = (len - 4) + } attribute_sequence[0]; + } signed_data; + + uint32_t signature_sequence_len; + struct : public len_prefixed { + uint32_t id; + len_prefixed_value signature; + } signature_sequence[0]; + + len_prefixed_value public_key; + } signer_sequence[0]; +}; + +// The structures above are just for documentation purpose +// The real parsing logic is the following + +string read_certificate(int fd) { + string certificate; + uint32_t size4; + uint64_t size8, size_of_block; + + for (int i = 0;; i++) { + unsigned short n; + lseek(fd, -i - 2, SEEK_END); + read(fd, &n, 2); + if (n == i) { + lseek(fd, -22, SEEK_CUR); + read(fd, &size4, 4); + if (size4 == 0x6054b50u) { // central directory end magic + break; + } + } + if (i == 0xffff) { + return certificate; + } + } + + lseek(fd, 12, SEEK_CUR); + + read(fd, &size4, 0x4); + lseek(fd, (off_t) (size4 - 0x18), SEEK_SET); + + read(fd, &size8, 0x8); + char magic[0x10] = {0}; + read(fd, magic, sizeof(magic)); + if (memcmp(magic, "APK Sig Block 42", sizeof(magic)) != 0) { + return certificate; + } + + lseek(fd, (off_t) (size4 - (size8 + 0x8)), SEEK_SET); + read(fd, &size_of_block, 0x8); + if (size_of_block != size8) { + return certificate; + } + + for (;;) { + uint32_t id; + uint32_t offset; + read(fd, &size8, 0x8); // sequence length + if (size8 == size_of_block) { + break; + } + read(fd, &id, 0x4); // id + offset = 4; + + if (id == 0x7109871au) { + read(fd, &size4, 0x4); // signer-sequence length + read(fd, &size4, 0x4); // signer length + read(fd, &size4, 0x4); // signed data length + offset += 0x4 * 3; + + read(fd, &size4, 0x4); // digests-sequence length + lseek(fd, (off_t) (size4), SEEK_CUR);// skip digests + offset += 0x4 + size4; + + read(fd, &size4, 0x4); // certificates length + read(fd, &size4, 0x4); // certificate length + offset += 0x4 * 2; + + certificate.resize(size4); + read(fd, certificate.data(), size4); + + offset += size4; + } + lseek(fd, (off_t) (size8 - offset), SEEK_CUR); + } + return certificate; +} diff --git a/native/jni/utils/files.cpp b/native/jni/utils/files.cpp index 0f4a9ea97..beebdd6d1 100644 --- a/native/jni/utils/files.cpp +++ b/native/jni/utils/files.cpp @@ -1,10 +1,7 @@ #include #include -#include #include #include -#include -#include #include #include @@ -57,12 +54,12 @@ static void post_order_walk(int dirfd, const Func &fn) { } } -enum visit_result { - CONTINUE, SKIP, TERMINATE +enum walk_result { + CONTINUE, SKIP, ABORT }; template -static visit_result pre_order_walk(int dirfd, const Func &fn) { +static walk_result pre_order_walk(int dirfd, const Func &fn) { auto dir = xopen_dir(dirfd); if (!dir) { close(dirfd); @@ -71,16 +68,17 @@ static visit_result pre_order_walk(int dirfd, const Func &fn) { for (dirent *entry; (entry = xreaddir(dir.get()));) { switch (fn(dirfd, entry)) { - case CONTINUE: - break; - case SKIP: - continue; - case TERMINATE: - return TERMINATE; + case CONTINUE: + break; + case SKIP: + continue; + case ABORT: + return ABORT; } if (entry->d_type == DT_DIR) { int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); - if (pre_order_walk(fd, fn) == TERMINATE) return TERMINATE; + if (pre_order_walk(fd, fn) == ABORT) + return ABORT; } } return CONTINUE; @@ -419,7 +417,7 @@ void backup_folder(const char *dir, vector &files) { char path[PATH_MAX]; xrealpath(dir, path); int len = strlen(path); - pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> visit_result { + pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> walk_result { int fd = xopenat(dfd, entry->d_name, O_RDONLY); if (fd < 0) return SKIP; @@ -526,13 +524,13 @@ mmap_data::mmap_data(const char *name, bool rw) { string find_apk_path(const char *pkg) { char buf[PATH_MAX]; - pre_order_walk(xopen("/data/app", O_RDONLY), [&](int dfd, dirent *entry) -> visit_result { + pre_order_walk(xopen("/data/app", O_RDONLY), [&](int dfd, dirent *entry) -> walk_result { if (entry->d_type != DT_DIR) return SKIP; size_t len = strlen(pkg); if (strncmp(entry->d_name, pkg, len) == 0 && entry->d_name[len] == '-') { fd_pathat(dfd, entry->d_name, buf, sizeof(buf)); - return TERMINATE; + return ABORT; } else if (strncmp(entry->d_name, "~~", 2) == 0) { return CONTINUE; } else return SKIP; @@ -540,82 +538,3 @@ string find_apk_path(const char *pkg) { string path(buf); return path.append("/base.apk"); } - -string read_certificate(string app_path) { - string certificate; - uint32_t size4; - uint64_t size8, size_of_block; - - int fd = xopen(app_path.data(), O_RDONLY); - if (fd < 0) { - return certificate; - } - run_finally f([&] { close(fd); }); - - for (int i = 0;; i++) { - unsigned short n; - lseek(fd, -i - 2, SEEK_END); - read(fd, &n, 2); - if (n == i) { - lseek(fd, -22, SEEK_CUR); - read(fd, &size4, 4); - if (size4 == 0x6054b50u) { // central directory end magic - break; - } - } - if (i == 0xffff) { - return certificate; - } - } - - lseek(fd, 12, SEEK_CUR); - - read(fd, &size4, 0x4); - lseek(fd, (off_t) (size4 - 0x18), SEEK_SET); - - read(fd, &size8, 0x8); - unsigned char buffer[0x10] = {0}; - read(fd, buffer, 0x10); - if (memcmp(buffer, "APK Sig Block 42", 0x10) != 0) { - return certificate; - } - - lseek(fd, (off_t) (size4 - (size8 + 0x8)), SEEK_SET); - read(fd, &size_of_block, 0x8); - if (size_of_block != size8) { - return certificate; - } - - for (;;) { - uint32_t id; - uint32_t offset; - read(fd, &size8, 0x8); // sequence length - if (size8 == size_of_block) { - break; - } - read(fd, &id, 0x4); // id - offset = 4; - - if (id == 0x7109871au) { - read(fd, &size4, 0x4); // signer-sequence length - read(fd, &size4, 0x4); // signer length - read(fd, &size4, 0x4); // signed data length - offset += 0x4 * 3; - - read(fd, &size4, 0x4); // digests-sequence length - lseek(fd, (off_t) (size4), SEEK_CUR);// skip digests - offset += 0x4 + size4; - - read(fd, &size4, 0x4); // certificates length - read(fd, &size4, 0x4); // certificate length - offset += 0x4 * 2; - - certificate.resize(size4); - read(fd, certificate.data(), size4); - - offset += size4; - } - lseek(fd, (off_t) (size8 - offset), SEEK_CUR); - } - return certificate; -} diff --git a/native/jni/utils/files.hpp b/native/jni/utils/files.hpp index 11be8e30e..8e005fe03 100644 --- a/native/jni/utils/files.hpp +++ b/native/jni/utils/files.hpp @@ -101,9 +101,7 @@ void clone_dir(int src, int dest); void parse_mnt(const char *file, const std::function &fn); void backup_folder(const char *dir, std::vector &files); void restore_folder(const char *dir, std::vector &files); - std::string find_apk_path(const char *pkg); -std::string read_certificate(std::string app_path); template void full_read(const char *filename, T &buf, size_t &size) {