mirror of
https://github.com/hyugogirubato/KeyDive.git
synced 2026-07-15 18:40:02 +02:00
support old std string impl
This commit is contained in:
+81
-12
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Date: 2025-06-21
|
* Date: 2026-04-26
|
||||||
* Description: DRM key extraction for research and educational purposes.
|
* Description: DRM key extraction for research and educational purposes.
|
||||||
* Source: https://github.com/hyugogirubato/KeyDive
|
* Source: https://github.com/hyugogirubato/KeyDive
|
||||||
*/
|
*/
|
||||||
@@ -47,23 +47,92 @@ Memory.readByteArray ??= (address, length) => address.readByteArray(length);
|
|||||||
Memory.readPointer ??= (address) => address.readPointer();
|
Memory.readPointer ??= (address) => address.readPointer();
|
||||||
Memory.readU16 ??= (address) => address.readU16();
|
Memory.readU16 ??= (address) => address.readU16();
|
||||||
|
|
||||||
|
// libc++ std::string (SSO flag at bit 0 of byte 0):
|
||||||
|
// short: [size<<1 : 1B][inline data @+1 ...]
|
||||||
|
// long: [bit0=1 : 1B][...][size_t length @+pSize][char* data ptr @+2*pSize]
|
||||||
|
// Bit 0 of the first byte selects short vs long; length read as U16.
|
||||||
|
// https://learnfrida.info/intermediate_usage/#stdstring
|
||||||
Memory.readStdString = function (address) {
|
Memory.readStdString = function (address) {
|
||||||
// https://learnfrida.info/intermediate_usage/#stdstring
|
const length = Memory.readU16(address.add(Process.pointerSize));
|
||||||
// Read string size (2 bytes) at offset pointerSize
|
|
||||||
const size = Memory.readU16(address.add(Process.pointerSize));
|
|
||||||
|
|
||||||
// Check if string is using Small String Optimization (SSO)
|
|
||||||
const LSB = address.readU8() & 1;
|
const LSB = address.readU8() & 1;
|
||||||
if (LSB === 0) {
|
if (LSB === 0) {
|
||||||
// https://codeshare.frida.re/@oleavr/read-std-string/
|
|
||||||
// SSO: data is stored inline starting at address + 1
|
// SSO: data is stored inline starting at address + 1
|
||||||
return Memory.readByteArray(address.add(1), size);
|
return Memory.readByteArray(address.add(1), length);
|
||||||
} else {
|
} else {
|
||||||
// Non-SSO: pointer to data is stored at address
|
// Non-SSO: pointer to data is stored at address
|
||||||
return Memory.readByteArray(address.add(Process.pointerSize * 2).readPointer(), size);
|
return Memory.readByteArray(address.add(Process.pointerSize * 2).readPointer(), length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// libstdc++ C++11 ABI:
|
||||||
|
// [char* _M_p][size_t length][SSO buf 16B or capacity]
|
||||||
|
// _M_p always points to the data (heap or local SSO buffer).
|
||||||
|
Memory.readStdStringGnuCxx11 = function (address) {
|
||||||
|
try {
|
||||||
|
const dataPtr = address.readPointer();
|
||||||
|
if (dataPtr.isNull() || dataPtr.compare(ptr(0x1000)) < 0) return null;
|
||||||
|
const length = address.add(Process.pointerSize).readU32();
|
||||||
|
if (length === 0 || length > 0x10000000) return null;
|
||||||
|
return Memory.readByteArray(dataPtr, length);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libstdc++ classic (pre-C++11) COW std::string:
|
||||||
|
// [char* _M_p @+0] + _Rep header before data: [length][capacity][refcount]
|
||||||
|
// Container is a single pointer; length sits 3*pSize before the data.
|
||||||
|
Memory.readStdStringGnuCow = function (address) {
|
||||||
|
try {
|
||||||
|
const dataPtr = address.readPointer();
|
||||||
|
if (dataPtr.isNull() || dataPtr.compare(ptr(0x1000)) < 0) return null;
|
||||||
|
const length = dataPtr.sub(3 * Process.pointerSize).readU32();
|
||||||
|
if (length === 0 || length > 0x10000000) return null;
|
||||||
|
return Memory.readByteArray(dataPtr, length);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 24-byte vector-style std::string (old MediaTek/ARMv7 Widevine):
|
||||||
|
// [SSO buf 12B][cap/alloc ptr][char* _M_finish][char* _M_start] (offsets 0/12/16/20)
|
||||||
|
// Length = _M_finish - _M_start (matches IDA *((_DWORD*)s+5)==*(s+4) empty check).
|
||||||
|
Memory.readStdStringRange = function (address) {
|
||||||
|
try {
|
||||||
|
const finish = address.add(16).readPointer();
|
||||||
|
const start = address.add(20).readPointer();
|
||||||
|
if (start.isNull() || start.compare(ptr(0x1000)) < 0) return null;
|
||||||
|
if (finish.compare(start) < 0) return null;
|
||||||
|
const length = finish.sub(start).toInt32();
|
||||||
|
if (length === 0 || length > 0x10000000) return null;
|
||||||
|
return Memory.readByteArray(start, length);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try every known std::string ABI and return the first plausible result.
|
||||||
|
Memory.readStdStringAny = function (address) {
|
||||||
|
const readers = [
|
||||||
|
Memory.readStdStringRange, // 24B vector-style (old MediaTek/ARMv7 Widevine)
|
||||||
|
Memory.readStdString, // libc++ (modern Android)
|
||||||
|
Memory.readStdStringGnuCxx11, // libstdc++ C++11 (old NDK GCC, _GLIBCXX_USE_CXX11_ABI=1)
|
||||||
|
Memory.readStdStringGnuCow, // libstdc++ pre-C++11 (very old NDK GCC)
|
||||||
|
];
|
||||||
|
for (const reader of readers) {
|
||||||
|
try {
|
||||||
|
const data = reader(address);
|
||||||
|
if (data && data.byteLength > 0) return data;
|
||||||
|
} catch (e) { /* try next */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy compact vector layout (learnfrida.info):
|
||||||
|
// [data ptr @+0][...][U16 size @+8]
|
||||||
|
// Doesn't match any current STL; kept as a last-resort fallback.
|
||||||
|
// https://learnfrida.info/intermediate_usage/#stdvector
|
||||||
Memory.readStdVector = function (address) {
|
Memory.readStdVector = function (address) {
|
||||||
// https://learnfrida.info/intermediate_usage/#stdvector
|
// https://learnfrida.info/intermediate_usage/#stdvector
|
||||||
// Read the vector size (2 bytes) at offset 8
|
// Read the vector size (2 bytes) at offset 8
|
||||||
@@ -310,7 +379,7 @@ function CdmLicense_PrepareKeyRequest(address) {
|
|||||||
for (let i = 0; i < this.params.length; i++) {
|
for (let i = 0; i < this.params.length; i++) {
|
||||||
// Extract the signed_request data (CdmKeyMessage*)
|
// Extract the signed_request data (CdmKeyMessage*)
|
||||||
try {
|
try {
|
||||||
const signedRequestData = Memory.readStdString(this.params[i]);
|
const signedRequestData = Memory.readStdStringAny(this.params[i]);
|
||||||
if (signedRequestData) {
|
if (signedRequestData) {
|
||||||
dumped = true;
|
dumped = true;
|
||||||
send('challenge', signedRequestData);
|
send('challenge', signedRequestData);
|
||||||
@@ -356,7 +425,7 @@ function CdmEngine_GenerateKeyRequest(address) {
|
|||||||
for (let i = 0; i < this.params.length; i++) {
|
for (let i = 0; i < this.params.length; i++) {
|
||||||
// Extract the signed_request data (CdmKeyMessage*)
|
// Extract the signed_request data (CdmKeyMessage*)
|
||||||
try {
|
try {
|
||||||
const signedRequestData = Memory.readStdString(this.params[i]);
|
const signedRequestData = Memory.readStdStringAny(this.params[i]);
|
||||||
if (signedRequestData) {
|
if (signedRequestData) {
|
||||||
dumped = true;
|
dumped = true;
|
||||||
send('challenge', signedRequestData);
|
send('challenge', signedRequestData);
|
||||||
@@ -383,7 +452,7 @@ function AesCbcKey_Encrypt(address) {
|
|||||||
*/
|
*/
|
||||||
Interceptor.attach(address, {
|
Interceptor.attach(address, {
|
||||||
onEnter: function (args) {
|
onEnter: function (args) {
|
||||||
const inData = Memory.readStdString(args[1]);
|
const inData = Memory.readStdStringAny(args[1]);
|
||||||
if (inData) {
|
if (inData) {
|
||||||
print(Level.DEBUG, '[*] AesCbcKey::Encrypt');
|
print(Level.DEBUG, '[*] AesCbcKey::Encrypt');
|
||||||
send('client_id', inData);
|
send('client_id', inData);
|
||||||
|
|||||||
Reference in New Issue
Block a user