void AndroidFormat::updateSha1Hash(BootImageHeader *hdr)
{
    SHA_CTX ctx;
    SHA_init(&ctx);

    SHA_update(&ctx, mI10e->kernelImage.data(), mI10e->kernelImage.size());
    SHA_update(&ctx, reinterpret_cast<char *>(&hdr->kernel_size),
               sizeof(hdr->kernel_size));

    SHA_update(&ctx, mI10e->ramdiskImage.data(), mI10e->ramdiskImage.size());
    SHA_update(&ctx, reinterpret_cast<char *>(&hdr->ramdisk_size),
               sizeof(hdr->ramdisk_size));
    if (!mI10e->secondImage.empty()) {
        SHA_update(&ctx, mI10e->secondImage.data(), mI10e->secondImage.size());
    }

    // Bug in AOSP? AOSP's mkbootimg adds the second bootloader size to the SHA1
    // hash even if it's 0
    SHA_update(&ctx, reinterpret_cast<char *>(&hdr->second_size),
               sizeof(hdr->second_size));

    if (!mI10e->dtImage.empty()) {
        SHA_update(&ctx, mI10e->dtImage.data(), mI10e->dtImage.size());
        SHA_update(&ctx, reinterpret_cast<char *>(&hdr->dt_size),
                   sizeof(hdr->dt_size));
    }

    std::memset(hdr->id, 0, sizeof(hdr->id));
    memcpy(hdr->id, SHA_final(&ctx), SHA_DIGEST_SIZE);

    std::string hexDigest = StringUtils::toHex(
            reinterpret_cast<const unsigned char *>(hdr->id), SHA_DIGEST_SIZE);

    FLOGD("Computed new ID hash: %s", hexDigest.c_str());
}
PatchFilePatcher::PatchFilePatcher(const PatcherConfig * const pc,
                                   const FileInfo * const info,
                                   const PatchInfo::AutoPatcherArgs &args)
    : m_impl(new Impl())
{
    m_impl->pc = pc;
    m_impl->info = info;
    m_impl->args = args;

    // The arguments should have the patch to the file
    if (args.find(ArgFile) == args.end()) {
        LOGW("Arguments does not contain the path to a patch file");
        return;
    }

    m_impl->patchFile = pc->dataDirectory() + "/patches/" + args.at(ArgFile);

    std::string contents;
    auto ret = FileUtils::readToString(m_impl->patchFile, &contents);
    if (!ret) {
        LOGW("Failed to read patch file");
        return;
    }

    std::vector<std::string> lines;
    boost::split(lines, contents, boost::is_any_of("\n"));

    const std::regex reOrigFile("---\\s+(.+?)(?:$|\t)");

    for (auto it = lines.begin(); it != lines.end(); ++it) {
        std::smatch what;

        if (std::regex_search(*it, what, reOrigFile)) {
            std::string file = what.str(1);
            if (boost::starts_with(file, "\"") && boost::ends_with(file, "\"")) {
                file.erase(file.begin());
                file.erase(file.end() - 1);
            }

            // Skip files containing escaped characters
            if (file.find("\\") != std::string::npos) {
                FLOGW("Skipping file with escaped characters in filename: {}", file);
                continue;
            }

            // Strip leading slash (-p1)
            auto it = file.find("/");
            if (it != std::string::npos) {
                file.erase(file.begin(), file.begin() + it + 1);
            }

            FLOGD("Found file in patch: {}", file);

            m_impl->files.push_back(file);
        }
    }
}
示例#3
0
bool LokiPatcher::patchImage(std::vector<unsigned char> *data,
                             std::vector<unsigned char> aboot)
{
    if (aboot.empty()) {
        FLOGE("[Loki] Aboot image cannot be empty");
        return false;
    }

    // Prevent reading out of bounds
    data->resize((data->size() + 0x2000 + 0xfff) & ~0xfff);
    aboot.resize((aboot.size() + 0xfff) & ~0xfff);

    uint32_t target = 0;
    uint32_t abootBase = *reinterpret_cast<uint32_t *>(aboot.data() + 12) - 0x28;

    // Find the signature checking function via pattern matching
    for (const unsigned char *ptr = aboot.data();
            ptr < aboot.data() + aboot.size() - 0x1000; ++ptr) {
        if (!memcmp(ptr, PATTERN1, 8) ||
                !memcmp(ptr, PATTERN2, 8) ||
                !memcmp(ptr, PATTERN3, 8) ||
                !memcmp(ptr, PATTERN4, 8) ||
                !memcmp(ptr, PATTERN5, 8)) {
            target = static_cast<uint32_t>(ptr - aboot.data() + abootBase);
            break;
        }
    }

    // Do a second pass for the second LG pattern. This is necessary because
    // apparently some LG models have both LG patterns, which throws off the
    // fingerprinting.

    if (!target) {
        for (const unsigned char *ptr = aboot.data();
                ptr < aboot.data() + aboot.size() - 0x1000; ++ptr) {
            if (memcmp(ptr, PATTERN6, 8) == 0) {
                target = static_cast<uint32_t>(ptr - aboot.data() + abootBase);
                break;
            }
        }
    }

    if (!target) {
        LOGE("[Loki] Failed to find function to patch");
        return false;
    }

    LokiTarget *tgt = nullptr;

    for (size_t i = 0; i < (sizeof(targets) / sizeof(targets[0])); ++i) {
        if (targets[i].check_sigs == target) {
            tgt = &targets[i];
            break;
        }
    }

    if (!tgt) {
        LOGE("[Loki] Unsupported aboot image");
        return false;
    }

    FLOGD("[Loki] Detected target %s %s build %s",
          tgt->vendor, tgt->device, tgt->build);

    BootImageHeader *hdr = reinterpret_cast<BootImageHeader *>(data->data());
    LokiHeader *lokiHdr = reinterpret_cast<LokiHeader *>(data->data() + 0x400);

    // Set the Loki header
    memcpy(lokiHdr->magic, LOKI_MAGIC, LOKI_MAGIC_SIZE);
    lokiHdr->recovery = 0;
    strncpy(lokiHdr->build, tgt->build, sizeof(lokiHdr->build) - 1);

    uint32_t pageSize = hdr->page_size;
    uint32_t pageMask = hdr->page_size - 1;

    uint32_t origKernelSize = hdr->kernel_size;
    uint32_t origRamdiskSize = hdr->ramdisk_size;

    FLOGD("[Loki] Original kernel address: 0x%08x", hdr->kernel_addr);
    FLOGD("[Loki] Original ramdisk address: 0x%08x", hdr->ramdisk_addr);

    // Store the original values in unused fields of the header
    lokiHdr->orig_kernel_size = origKernelSize;
    lokiHdr->orig_ramdisk_size = origRamdiskSize;
    lokiHdr->ramdisk_addr = hdr->kernel_addr +
            ((hdr->kernel_size + pageMask) & ~pageMask);

    unsigned char patch[] = LOKI_SHELLCODE;
    if (!patchShellcode(tgt->hdr, hdr->ramdisk_addr, patch)) {
        LOGE("[Loki] Failed to patch shellcode");
        return false;
    }

    // Ramdisk must be aligned to a page boundary
    hdr->kernel_size = ((hdr->kernel_size + pageMask) & ~pageMask) +
            hdr->ramdisk_size;

    // Guarantee 16-byte alignment
    int offset = tgt->check_sigs & 0xf;

    hdr->ramdisk_addr = tgt->check_sigs - offset;

    int fakeSize;

    if (tgt->lg) {
        fakeSize = pageSize;
        hdr->ramdisk_size = pageSize;
    } else {
        fakeSize = 0x200;
        hdr->ramdisk_size = 0;
    }

    std::vector<unsigned char> newImage;

    if (pageSize > data->size()) {
        FLOGE("[Loki] Header exceeds boot image size by %" PRIzu " bytes",
              pageSize - data->size());
        return false;
    }

    // Write the image header
    newImage.insert(newImage.end(),
                    data->data(),
                    data->data() + pageSize);

    uint32_t pageKernelSize = (origKernelSize + pageMask) & ~pageMask;

    if (pageSize + pageKernelSize > data->size()) {
        FLOGE("[Loki] Kernel exceeds boot image size by %" PRIzu " bytes",
              pageSize + pageKernelSize - data->size());
        return false;
    }

    // Write the kernel
    newImage.insert(newImage.end(),
                    data->data() + pageSize,
                    data->data() + pageSize + pageKernelSize);

    uint32_t pageRamdiskSize = (origRamdiskSize + pageMask) & ~pageMask;

    if (pageSize + pageKernelSize + pageRamdiskSize > data->size()) {
        FLOGE("[Loki] Ramdisk exceeds boot image size by %" PRIzu " bytes",
              pageSize + pageKernelSize + pageRamdiskSize - data->size());
        return false;
    }

    // Write the ramdisk
    newImage.insert(newImage.end(),
                    data->data() + pageSize + pageKernelSize,
                    data->data() + pageSize + pageKernelSize + pageRamdiskSize);

    if (tgt->check_sigs - abootBase - offset + fakeSize > aboot.size()) {
        FLOGE("[Loki] Requested aboot segment exceeds aboot size by %" PRIzu " bytes",
              tgt->check_sigs - abootBase - offset + fakeSize - aboot.size());
        return false;
    }

    // Write fake size bytes of original code to the output
    newImage.insert(newImage.end(),
                    aboot.data() + tgt->check_sigs - abootBase - offset,
                    aboot.data() + tgt->check_sigs - abootBase - offset + fakeSize);

    // Save this position for later
    uint32_t pos = newImage.size();

    if (hdr->dt_size) {
        LOGD("[Loki] Writing device tree");

        if (pageSize + pageKernelSize + pageRamdiskSize + hdr->dt_size > data->size()) {
            FLOGE("[Loki] Device tree image exceeds boot image size by %" PRIzu " bytes",
                  pageSize + pageKernelSize + pageRamdiskSize + hdr->dt_size - data->size());
            return false;
        }

        newImage.insert(newImage.end(),
                        data->data() + pageSize + pageKernelSize + pageRamdiskSize,
                        data->data() + pageSize + pageKernelSize + pageRamdiskSize + hdr->dt_size);
    }

    // Write the patch
    memcpy(newImage.data() + pos - (fakeSize - offset), patch, sizeof(patch));

    LOGD("[Loki] Patching completed");

    data->swap(newImage);

    return true;
}
示例#4
0
void EdifyTokenizer::dump(const std::vector<EdifyToken *> &tokens)
{
    const char *tokenName = nullptr;

    for (std::size_t i = 0; i < tokens.size(); ++i) {
        EdifyToken *t = tokens[i];

        switch (t->type()) {
        case EdifyTokenType::If:
            tokenName = "If";
            break;
        case EdifyTokenType::Then:
            tokenName = "Then";
            break;
        case EdifyTokenType::Else:
            tokenName = "Else";
            break;
        case EdifyTokenType::Endif:
            tokenName = "Endif";
            break;
        case EdifyTokenType::And:
            tokenName = "And";
            break;
        case EdifyTokenType::Or:
            tokenName = "Or";
            break;
        case EdifyTokenType::Equals:
            tokenName = "Equals";
            break;
        case EdifyTokenType::NotEquals:
            tokenName = "NotEquals";
            break;
        case EdifyTokenType::Not:
            tokenName = "Not";
            break;
        case EdifyTokenType::LeftParen:
            tokenName = "LeftParen";
            break;
        case EdifyTokenType::RightParen:
            tokenName = "RightParen";
            break;
        case EdifyTokenType::Semicolon:
            tokenName = "Semicolon";
            break;
        case EdifyTokenType::Comma:
            tokenName = "Comma";
            break;
        case EdifyTokenType::Concat:
            tokenName = "Concat";
            break;
        case EdifyTokenType::Newline:
            tokenName = "Newline";
            break;
        case EdifyTokenType::Whitespace:
            tokenName = "Whitespace";
            break;
        case EdifyTokenType::Comment:
            tokenName = "Comment";
            break;
        case EdifyTokenType::String:
            tokenName = "String";
            break;
        case EdifyTokenType::Unknown:
            tokenName = "Unknown";
            break;
        }

        FLOGD("%" PRIzu ": %-20s: %s", i, tokenName, t->generate().c_str());
    }
}
bool AndroidFormat::loadImage(const unsigned char *data, std::size_t size)
{
    std::size_t headerIndex;
    if (!findHeader(data, size, 512, &headerIndex)) {
        LOGE("Failed to find Android header in boot image");
        return false;
    }

    FLOGD("Found Android boot image header at: %" PRIzu, headerIndex);

    if (!loadHeader(data, size, headerIndex)) {
        return false;
    }

    uint32_t pos = 0;

    // Save kernel image
    pos += sizeof(BootImageHeader);
    pos += skipPadding(sizeof(BootImageHeader), mI10e->pageSize);
    if (pos + mI10e->hdrKernelSize > size) {
        FLOGE("Kernel image exceeds boot image size by %" PRIzu " bytes",
              pos + mI10e->hdrKernelSize - size);
        return false;
    }

    mI10e->kernelImage.assign(data + pos, data + pos + mI10e->hdrKernelSize);

    // Save ramdisk image
    pos += mI10e->hdrKernelSize;
    pos += skipPadding(mI10e->hdrKernelSize, mI10e->pageSize);
    if (pos + mI10e->hdrRamdiskSize > size) {
        FLOGE("Ramdisk image exceeds boot image size by %" PRIzu " bytes",
              pos + mI10e->hdrRamdiskSize - size);
        return false;
    }

    mI10e->ramdiskImage.assign(data + pos, data + pos + mI10e->hdrRamdiskSize);

    // Save second bootloader image
    pos += mI10e->hdrRamdiskSize;
    pos += skipPadding(mI10e->hdrRamdiskSize, mI10e->pageSize);
    if (pos + mI10e->hdrSecondSize > size) {
        FLOGE("Second bootloader image exceeds boot image size by %" PRIzu " bytes",
              pos + mI10e->hdrSecondSize - size);
        return false;
    }

    // The second bootloader may not exist
    if (mI10e->hdrSecondSize > 0) {
        mI10e->secondImage.assign(data + pos, data + pos + mI10e->hdrSecondSize);
    } else {
        mI10e->secondImage.clear();
    }

    // Save device tree image
    pos += mI10e->hdrSecondSize;
    pos += skipPadding(mI10e->hdrSecondSize, mI10e->pageSize);
    if (pos + mI10e->hdrDtSize > size) {
        std::size_t diff = pos + mI10e->hdrDtSize - size;

        FLOGE("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING");
        FLOGE("THIS BOOT IMAGE MAY NO LONGER BE BOOTABLE. YOU HAVE BEEN WARNED");
        FLOGE("Device tree image exceeds boot image size by %" PRIzu
              " bytes and HAS BEEN TRUNCATED", diff);
        FLOGE("WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING");

        mI10e->dtImage.assign(data + pos, data + pos + mI10e->hdrDtSize - diff);
    } else {
        mI10e->dtImage.assign(data + pos, data + pos + mI10e->hdrDtSize);
    }

    // The device tree image may not exist as well
    if (mI10e->hdrDtSize == 0) {
        mI10e->dtImage.clear();
    }

    pos += mI10e->hdrDtSize;
    pos += skipPadding(mI10e->hdrDtSize, mI10e->pageSize);

    return true;
}
void AndroidFormat::dumpHeader(const BootImageHeader *hdr)
{
    FLOGD("- magic:        %s",
          std::string(hdr->magic, hdr->magic + BOOT_MAGIC_SIZE).c_str());
    FLOGD("- kernel_size:  %u",     hdr->kernel_size);
    FLOGD("- kernel_addr:  0x%08x", hdr->kernel_addr);
    FLOGD("- ramdisk_size: %u",     hdr->ramdisk_size);
    FLOGD("- ramdisk_addr: 0x%08x", hdr->ramdisk_addr);
    FLOGD("- second_size:  %u",     hdr->second_size);
    FLOGD("- second_addr:  0x%08x", hdr->second_addr);
    FLOGD("- tags_addr:    0x%08x", hdr->tags_addr);
    FLOGD("- page_size:    %u",     hdr->page_size);
    FLOGD("- dt_size:      %u",     hdr->dt_size);
    FLOGD("- unused:       0x%08x", hdr->unused);
    FLOGD("- name:         %s",     StringUtils::toMaxString(
          reinterpret_cast<const char *>(hdr->name), BOOT_NAME_SIZE).c_str());
    FLOGD("- cmdline:      %s",     StringUtils::toMaxString(
          reinterpret_cast<const char *>(hdr->cmdline), BOOT_ARGS_SIZE).c_str());
    FLOGD("- id:           %s",     StringUtils::toHex(
          reinterpret_cast<const unsigned char *>(hdr->id), 32).c_str());
}