mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 05:07:37 +00:00
More detailed comments and documentation
This commit is contained in:
parent
9f7a3db8be
commit
575c417403
@ -2,9 +2,13 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define APK_SIGNING_BLOCK_MAGIC "APK Sig Block 42"
|
||||
#define SIGNATURE_SCHEME_V2_MAGIC 0x7109871a
|
||||
#define EOCD_MAGIC 0x6054b50
|
||||
|
||||
// Top-level block container
|
||||
struct signing_block {
|
||||
uint64_t len;
|
||||
uint64_t block_sz;
|
||||
|
||||
struct id_value_pair {
|
||||
uint64_t len;
|
||||
@ -14,7 +18,7 @@ struct signing_block {
|
||||
};
|
||||
} id_value_pair_sequence[0];
|
||||
|
||||
uint64_t block_len; // *MUST* be same as len
|
||||
uint64_t block_sz_; // *MUST* be same as block_sz
|
||||
char magic[16]; // "APK Sig Block 42"
|
||||
};
|
||||
|
||||
@ -59,78 +63,124 @@ struct v2_signature {
|
||||
} signer_sequence[0];
|
||||
};
|
||||
|
||||
// The structures above are just for documentation purpose
|
||||
// The real parsing logic is the following
|
||||
// End of central directory record
|
||||
struct EOCD {
|
||||
uint32_t magic; // 0x6054b50
|
||||
uint8_t pad[8]; // 8 bytes of irrelevant data
|
||||
uint32_t central_dir_sz; // size of central directory
|
||||
uint32_t central_dir_off; // offset of central directory
|
||||
uint16_t comment_sz; // size of comment
|
||||
char comment[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* A v2/v3 signed APK has the format as following
|
||||
*
|
||||
* +---------------+
|
||||
* | zip content |
|
||||
* +---------------+
|
||||
* | signing block |
|
||||
* +---------------+
|
||||
* | central dir |
|
||||
* +---------------+
|
||||
* | EOCD |
|
||||
* +---------------+
|
||||
*
|
||||
* Scan from end of file to find EOCD, and figure our way back to the
|
||||
* offset of the signing block. Next, directly extract the certificate
|
||||
* from the v2 signature block.
|
||||
*
|
||||
* All structures above are mostly just for documentation purpose.
|
||||
*
|
||||
* This method extracts the first certificate of the first signer
|
||||
* within the APK v2 signature block.
|
||||
*/
|
||||
string read_certificate(int fd) {
|
||||
string certificate;
|
||||
uint32_t size4;
|
||||
uint64_t size8, size_of_block;
|
||||
uint64_t size8;
|
||||
|
||||
// Find EOCD
|
||||
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
|
||||
// i is the absolute offset to end of file
|
||||
uint16_t comment_sz = 0;
|
||||
lseek(fd, -((off_t) sizeof(comment_sz)) - i, SEEK_END);
|
||||
read(fd, &comment_sz, sizeof(comment_sz));
|
||||
if (comment_sz == i) {
|
||||
// Double check if we actually found the structure
|
||||
lseek(fd, -((off_t) sizeof(EOCD)), SEEK_CUR);
|
||||
uint32_t magic = 0;
|
||||
read(fd, &magic, sizeof(magic));
|
||||
if (magic == EOCD_MAGIC) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 0xffff) {
|
||||
return certificate;
|
||||
// Comments cannot be longer than 0xffff (overflow), abort
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
lseek(fd, 12, SEEK_CUR);
|
||||
// We are now at EOCD + sizeof(magic)
|
||||
// Seek and read central_dir_off to find start of central directory
|
||||
uint32_t central_dir_off = 0;
|
||||
{
|
||||
constexpr off_t off = offsetof(EOCD, central_dir_off) - sizeof(EOCD::magic);
|
||||
lseek(fd, off, SEEK_CUR);
|
||||
}
|
||||
read(fd, ¢ral_dir_off, sizeof(central_dir_off));
|
||||
|
||||
read(fd, &size4, 0x4);
|
||||
lseek(fd, (off_t) (size4 - 0x18), SEEK_SET);
|
||||
|
||||
read(fd, &size8, 0x8);
|
||||
char magic[0x10] = {0};
|
||||
// Next, find the start of the APK signing block
|
||||
{
|
||||
constexpr int off = sizeof(signing_block::block_sz_) + sizeof(signing_block::magic);
|
||||
lseek(fd, (off_t) (central_dir_off - off), SEEK_SET);
|
||||
}
|
||||
read(fd, &size8, sizeof(size8)); // size8 = block_sz_
|
||||
char magic[sizeof(signing_block::magic)] = {0};
|
||||
read(fd, magic, sizeof(magic));
|
||||
if (memcmp(magic, "APK Sig Block 42", sizeof(magic)) != 0) {
|
||||
return certificate;
|
||||
if (memcmp(magic, APK_SIGNING_BLOCK_MAGIC, sizeof(magic)) != 0) {
|
||||
// Invalid signing block magic, abort
|
||||
return {};
|
||||
}
|
||||
uint64_t signing_blk_sz = 0;
|
||||
lseek(fd, (off_t) (central_dir_off - size8 - sizeof(signing_blk_sz)), SEEK_SET);
|
||||
read(fd, &signing_blk_sz, sizeof(signing_blk_sz));
|
||||
if (signing_blk_sz != size8) {
|
||||
// block_sz != block_sz_, invalid signing block format, abort
|
||||
return {};
|
||||
}
|
||||
|
||||
lseek(fd, (off_t) (size4 - (size8 + 0x8)), SEEK_SET);
|
||||
read(fd, &size_of_block, 0x8);
|
||||
if (size_of_block != size8) {
|
||||
return certificate;
|
||||
}
|
||||
// Finally, we are now at the beginning of the id-value pair sequence
|
||||
|
||||
for (;;) {
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
read(fd, &size8, 0x8); // sequence length
|
||||
if (size8 == size_of_block) {
|
||||
read(fd, &size8, sizeof(size8)); // id-value pair length
|
||||
if (size8 == signing_blk_sz) {
|
||||
// Outside of the id-value pair sequence; actually reading block_sz_
|
||||
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;
|
||||
uint32_t id;
|
||||
read(fd, &id, sizeof(id));
|
||||
if (id == SIGNATURE_SCHEME_V2_MAGIC) {
|
||||
read(fd, &size4, sizeof(size4)); // signer sequence length
|
||||
|
||||
read(fd, &size4, 0x4); // digests-sequence length
|
||||
lseek(fd, (off_t) (size4), SEEK_CUR);// skip digests
|
||||
offset += 0x4 + size4;
|
||||
read(fd, &size4, sizeof(size4)); // signer length
|
||||
read(fd, &size4, sizeof(size4)); // signed data length
|
||||
|
||||
read(fd, &size4, 0x4); // certificates length
|
||||
read(fd, &size4, 0x4); // certificate length
|
||||
offset += 0x4 * 2;
|
||||
read(fd, &size4, sizeof(size4)); // digest sequence length
|
||||
lseek(fd, (off_t) (size4), SEEK_CUR); // skip all digests
|
||||
|
||||
certificate.resize(size4);
|
||||
read(fd, certificate.data(), size4);
|
||||
read(fd, &size4, sizeof(size4)); // cert sequence length
|
||||
read(fd, &size4, sizeof(size4)); // cert length
|
||||
|
||||
offset += size4;
|
||||
string cert;
|
||||
cert.resize(size4);
|
||||
read(fd, cert.data(), size4);
|
||||
|
||||
return cert;
|
||||
} else {
|
||||
// Skip this id-value pair
|
||||
lseek(fd, (off_t) (size8 - sizeof(id)), SEEK_CUR);
|
||||
}
|
||||
lseek(fd, (off_t) (size8 - offset), SEEK_CUR);
|
||||
}
|
||||
return certificate;
|
||||
return {};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user