mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
81145ed0e9
- Improved error messages - Added shutdown functionality from mass stoage - Fixed an issue where 9006 would incorrectly be used for rebooting from mass storage - Added support for gathering security information from older flash apps - Added a new indicator in the empty view when a phone in bootloader mode is detected - Fixed an issue where interrupting the bootloader may fail - Added more checks to some functions - Started to work on a bootloader view - Fixed an issue where x50 phones in label mode would not get detected once being disconnected - Added logging for Qualcomm Emergency Charging mode - General bug fixes
167 lines
8.2 KiB
C#
167 lines
8.2 KiB
C#
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
// to deal in the Software without restriction, including without limitation
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace WPinternals
|
|
{
|
|
internal enum QualcommPartitionHeaderType
|
|
{
|
|
Long,
|
|
Short
|
|
};
|
|
|
|
internal class QualcommPartition
|
|
{
|
|
internal byte[] Binary;
|
|
internal uint HeaderOffset;
|
|
internal QualcommPartitionHeaderType HeaderType;
|
|
internal uint ImageOffset;
|
|
internal uint ImageAddress;
|
|
internal uint ImageSize;
|
|
internal uint CodeSize;
|
|
internal uint SignatureAddress;
|
|
internal uint SignatureSize;
|
|
internal uint SignatureOffset;
|
|
internal uint CertificatesAddress;
|
|
internal uint CertificatesSize;
|
|
internal uint CertificatesOffset;
|
|
internal byte[] RootKeyHash = null;
|
|
|
|
internal QualcommPartition(string Path) : this(File.ReadAllBytes(Path)) { }
|
|
|
|
internal QualcommPartition(byte[] Binary, uint Offset = 0)
|
|
{
|
|
#if DEBUG
|
|
System.Diagnostics.Debug.Print("Loader: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, 0, Binary.Length), ""));
|
|
#endif
|
|
|
|
this.Binary = Binary;
|
|
|
|
byte[] LongHeaderPattern = new byte[] { 0xD1, 0xDC, 0x4B, 0x84, 0x34, 0x10, 0xD7, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|
byte[] LongHeaderMask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
if (ByteOperations.FindPattern(Binary, Offset, 4, new byte[] { 0x7F, 0x45, 0x4C, 0x46 }, new byte[] { 0x00, 0x00, 0x00, 0x00 }, null) == 0)
|
|
{
|
|
// This is an ELF image
|
|
// First program header is a reference to the elf-header
|
|
// Second program header is a reference to the signed hash-table
|
|
HeaderType = QualcommPartitionHeaderType.Short;
|
|
UInt32 ProgramHeaderOffset;
|
|
UInt16 ProgramHeaderEntrySize;
|
|
UInt32 HashTableProgramHeaderOffset;
|
|
if (Binary[Offset + 0x04] == 1)
|
|
{
|
|
// 32-bit elf image
|
|
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x1c);
|
|
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x2a);
|
|
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
|
|
ImageOffset = Offset + ByteOperations.ReadUInt32(Binary, HashTableProgramHeaderOffset + 0x04);
|
|
HeaderOffset = ImageOffset + 8;
|
|
}
|
|
else if (Binary[Offset + 0x04] == 2)
|
|
{
|
|
// 64-bit elf image
|
|
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x20);
|
|
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x36);
|
|
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
|
|
ImageOffset = Offset + (UInt32)ByteOperations.ReadUInt64(Binary, HashTableProgramHeaderOffset + 0x08);
|
|
HeaderOffset = ImageOffset + 8;
|
|
}
|
|
else
|
|
throw new WPinternalsException("Invalid programmer", "The type of elf image could not be determined from the provided programmer.");
|
|
}
|
|
else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null)
|
|
{
|
|
HeaderType = QualcommPartitionHeaderType.Short;
|
|
ImageOffset = Offset;
|
|
HeaderOffset = ImageOffset + 8;
|
|
}
|
|
else
|
|
{
|
|
HeaderType = QualcommPartitionHeaderType.Long;
|
|
ImageOffset = Offset;
|
|
HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length;
|
|
}
|
|
|
|
if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
|
|
ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00);
|
|
else if (HeaderType == QualcommPartitionHeaderType.Short)
|
|
ImageOffset += 0x28;
|
|
else
|
|
ImageOffset += 0x50;
|
|
|
|
ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04);
|
|
ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08);
|
|
CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C);
|
|
SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10);
|
|
SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14);
|
|
SignatureOffset = SignatureAddress - ImageAddress + ImageOffset;
|
|
CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18);
|
|
CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C);
|
|
CertificatesOffset = CertificatesAddress - ImageAddress + ImageOffset;
|
|
|
|
uint CurrentCertificateOffset = CertificatesOffset;
|
|
uint CertificateSize = 0;
|
|
while (CurrentCertificateOffset < (CertificatesOffset + CertificatesSize))
|
|
{
|
|
if ((Binary[CurrentCertificateOffset] == 0x30) && (Binary[CurrentCertificateOffset + 1] == 0x82))
|
|
{
|
|
CertificateSize = (uint)(Binary[CurrentCertificateOffset + 2] * 0x100) + Binary[CurrentCertificateOffset + 3] + 4; // Big endian!
|
|
|
|
if ((CurrentCertificateOffset + CertificateSize) == (CertificatesOffset + CertificatesSize))
|
|
{
|
|
// This is the last certificate. So this is the root key.
|
|
RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize);
|
|
|
|
#if DEBUG
|
|
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
|
|
#endif
|
|
}
|
|
#if DEBUG
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize), ""));
|
|
}
|
|
#endif
|
|
CurrentCertificateOffset += CertificateSize;
|
|
}
|
|
else
|
|
{
|
|
if ((RootKeyHash == null) && (CurrentCertificateOffset > CertificatesOffset))
|
|
{
|
|
CurrentCertificateOffset -= CertificateSize;
|
|
|
|
// This is the last certificate. So this is the root key.
|
|
RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize);
|
|
|
|
#if DEBUG
|
|
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|