Skip to content

Instantly share code, notes, and snippets.

@14roiron
Created March 24, 2024 21:25
Show Gist options
  • Save 14roiron/77fb45ef17576f727d3e2b87e81d4f6f to your computer and use it in GitHub Desktop.
Save 14roiron/77fb45ef17576f727d3e2b87e81d4f6f to your computer and use it in GitHub Desktop.
/*
to launch on a root device:
https://blog.huli.tw/2023/04/27/en/android-apk-decompile-intro-4/
Term1:
adb shell
su /data/local/tmp/frida-server &
Term2:
frida -U -l Frida.js -f "com.cxw.zhiguang"
It may raise an error, as the sharelib is not loaded yet,
Best way is then to modify and save the js, it will be reloaded.
*/
Java.perform(function () {
// Hooking into the BLERequest class
var BLERequestClass = Java.use("com.cxw.cxwblelight.core.bluetooth.BLERequest");
// Hooking sendMessage method with specific overload
BLERequestClass.sendMessage.overload('byte', '[B', 'byte', '[B', 'long').implementation = function (b, bArr, b2, bArr2, j) {
// Print call trace
var Log = Java.use('android.util.Log');
var Exception = Java.use('java.lang.Exception');
// console.log("Call trace:\n" + Log.getStackTraceString(Exception.$new()));
console.log(`sendMessage (1st overload) called with params: b: ${b} bArr: ${byteArrayToHex(bArr)} b2: ${b2} bArr2: ${byteArrayToHex(bArr2)} j: ${j}`);
return this.sendMessage(b, bArr, b2, bArr2, j);
};
// Example of another sendMessage overload - Adjust based on actual signatures
// For demonstration purposes only
BLERequestClass.sendMessage.overload('byte', '[B', 'byte', '[B').implementation = function (b, bArr, b2, bArr2) {
console.log(`sendMessage (2nd overload) called with params: b: ${b} bArr: ${byteArrayToHex(bArr)} b2: ${b2} bArr2: ${byteArrayToHex(bArr2)}`);
return this.sendMessage(b, bArr, b2, bArr2);
};
var MSC26Class = Java.use("com.iflytek.msc26.MSC26");
// Hooking getAdvData to print its parameters and the result of calling msc26
BLERequestClass.getAdvData.implementation = function (b, bArr) {
console.log("[getAdvData] b: " + b + ", bArr: " + byteArrayToHex(bArr));
// Get groupId and sn values via their methods (they seem to be part of BLERequestClass)
var groupId = this.getGroupId();
var sn = this.getSN();
console.log("[getAdvData] mMAC: " + byteArrayToHex(this.mMAC.value) + ", mUUID: " + byteArrayToHex(this.mUUID.value) + ", groupId: " + groupId + ", sn: " + sn);
// Call the original getAdvData method
var result = this.getAdvData(b, bArr);
// Log the result
console.log("[getAdvData] Result: " + byteArrayToHex(result));
return result;
};
/*Optionally hook msc26 directly to print its parameters
MSC26Class.msc26.implementation = function (mMAC, mUUID, groupId, b, sn, bArr) {
console.log("[msc26] mMAC: " + byteArrayToHex(mMAC) + ", mUUID: " + byteArrayToHex(mUUID) + ", groupId: " + groupId + ", b: " + b + ", sn: " + sn + ", bArr: " + byteArrayToHex(bArr));
// Call the original msc26 method
var result = this.msc26(mMAC, mUUID, groupId, b, sn, bArr);
// Log the result
console.log("[msc26] Result: " + byteArrayToHex(result));
return result;
};//*/
// Optionally hook msc26 directly to print its parameters
MSC26Class.msc26.implementation = function (mMAC, mUUID, mUUID1, groupId, b, sn, bArr) {
console.log("[msc26] mMAC: " + byteArrayToHex(mMAC) + ", mUUID: " + byteArrayToHex(mUUID) + ", mUUID1: " + byteArrayToHex(mUUID1) +", groupId: " + groupId + ", b: " + b + ", sn: " + sn + ", bArr: " + byteArrayToHex(bArr));
// Call the original msc26 method
var result = this.msc26(mMAC, mUUID,mUUID1, groupId, b, sn, bArr);
// Log the result
console.log("[msc26] Result: " + byteArrayToHex(result));
return result;
};
// Helper function to convert byteArray to Hex string
function byteArrayToHex(byteArray) {
//return Java.array('byte', byteArray);
const HexClass = Java.use('org.apache.commons.codec.binary.Hex');
const StringClass = Java.use('java.lang.String');
const hexChars = HexClass.encodeHex(byteArray);
return StringClass.$new(hexChars).toString();
}
var BLERequestClass = Java.use("com.cxw.cxwblelight.core.bluetooth.BLERequest");
// Hooking setBeganBrightness method
BLERequestClass.setBeganBrightness.implementation = function (i, i2) {
console.log("[*] setBeganBrightness called with params:");
console.log(" i: " + i);
console.log(" i2: " + i2);
// Call the original method
this.setBeganBrightness(i, i2);
console.log("[+] setBeganBrightness executed successfully");
};
// Hooking setEndedBrightness method
BLERequestClass.setEndedBrightness.implementation = function (i, i2) {
console.log("[*] setEndedBrightness called with params:");
console.log(" i: " + i);
console.log(" i2: " + i2);
// Call the original method
this.setEndedBrightness(i, i2);
console.log("[+] setEndedBrightness executed successfully");
// Since the method is void, playVibrate is part of this method's execution
};
});
// Replace 'an_exported_function_from_MSC26' with an actual exported function name from msc26
// This is used to ensure msc26 is loaded.
var libraryLoaded = false;
var targetFunctionName = 'get_rf_payload';
function waitForLibraryLoad() {
// Check if the library is already loaded (optional)
var modules = Process.enumerateModules();
for (var i = 0; i < modules.length; i++) {
//console.log(`${modules[i].name} `);
if (modules[i].name === 'libmsc26.so') {
libraryLoaded = true;
console.log(`libmsc26 found ---------------`);
hookTargetFunction();
return;
}
}
// Wait for any function from msc26 to be called
Interceptor.attach(Module.findExportByName('libmsc26.so', 'Java_com_iflytek_msc26_MSC26_msc26'), {
onEnter: function (args) {
console.log(`${targetFunctionName} called`);
if (!libraryLoaded) {
libraryLoaded = true;
hookTargetFunction();
// Optionally detach the interceptor if it's no longer needed
//this.detach();
}
}
});
}
function hookTargetFunction() {
var targetFunctionAddress = Module.findExportByName('libmsc26.so', targetFunctionName);
if (targetFunctionAddress !== null) {
Interceptor.attach(targetFunctionAddress, {
onEnter: function (args) {
console.log(`${targetFunctionName} called`);
// Assuming 'address' is binary data, but if it's a string, use Memory.readUtf8String(args[0])
let addressHex = "Address (Hex): ";
for (let i = 0; i < args[1].toInt32(); ++i) {
const byte = Memory.readU8(args[0].add(i));
addressHex += byte.toString(16).padStart(2, '0') + " ";
}
console.log(addressHex);
console.log("Address Length: " + args[1].toInt32());
let rfPayloadHex = "RF Payload (Hex): ";
for (let i = 0; i < args[3].toInt32(); ++i) {
const byte = Memory.readU8(args[2].add(i));
rfPayloadHex += byte.toString(16).padStart(2, '0') + " ";
}
console.log(rfPayloadHex);
console.log("RF Payload Width: " + args[3].toInt32());
this.output_ble_payload = args[4];
},
onLeave: function (retval) {
let outputDataHex = "OutPutData (Hex): ";
for (let i = 0; i < 16; ++i) {
const byte = Memory.readU8(this.output_ble_payload.add(i));
outputDataHex += byte.toString(16).padStart(2, '0') + " ";
}
console.log(outputDataHex);
}
});
} else {
console.log(`${targetFunctionName} not found in msc26`);
}
/*
Interceptor.attach(Module.findExportByName("libmsc26.so", "check_crc16"), {
onEnter: function (args) {
this.log = "check_crc16 called with parameters:\n";
// Log 'addr' in hex format
let addrHex = "addr (Hex): ";
for (let i = 0; i < args[1].toInt32(); ++i) {
const byte = Memory.readU8(args[0].add(i));
addrHex += "0x"+byte.toString(16).padStart(2, '0') + ", ";
}
this.log += addrHex + "\n";
this.log += "addr_length: " + args[1].toInt32() + "\n";
// Log 'rf_payload' in hex format
let rfPayloadHex = "rf_payload (Hex): ";
for (let i = 0; i < args[3].toInt32(); ++i) {
const byte = Memory.readU8(args[2].add(i));
rfPayloadHex += "0x"+byte.toString(16).padStart(2, '0') + ", ";
}
this.log += rfPayloadHex + "\n";
this.log += "payload_width: " + args[3].toInt32();
},
onLeave: function (retval) {
// Log the return value
let returnValueHex = "Return value (CRC16): 0x" + retval.toInt32().toString(16).padStart(4, '0');
this.log += "\n" + returnValueHex;
console.log(this.log);
}
});
Interceptor.attach(Module.findExportByName("libmsc26.so", "whitening_encode"), {
onEnter: function (args) {
this.log = "whitening_encode called with parameters:\n";
// Log 'data' in hex format (before execution)
let dataHexBefore = "data before (Hex): ";
for (let i = 0; i < args[1].toInt32(); ++i) {
const byte = Memory.readU8(args[0].add(i));
dataHexBefore += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
this.log += dataHexBefore + "\n";
// Store arguments for use in onLeave
this.dataPtr = args[0];
this.length = args[1].toInt32();
this.regPtr = args[2];
this.log += "length: " + this.length + "\n";
// Log 'reg' before execution
let regBefore = "reg before (Hex): ";
for (let i = 0; i < 7; ++i) {
const value = Memory.readS32(this.regPtr.add(i * 4));
regBefore += "0x" + value.toString(16).padStart(8, '0') + ", ";
}
this.log += regBefore + "\n";
},
onLeave: function (retval) {
// Log 'data' in hex format (after execution)
let dataHexAfter = "data after (Hex): ";
for (let i = 0; i < this.length; ++i) {
const byte = Memory.readU8(this.dataPtr.add(i));
dataHexAfter += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
this.log += dataHexAfter + "\n";
// Log 'reg' after execution
let regAfter = "reg after (Hex): ";
for (let i = 0; i < 7; ++i) {
const value = Memory.readS32(this.regPtr.add(i * 4));
regAfter += "0x" + value.toString(16).padStart(8, '0') + ", ";
}
this.log += regAfter;
console.log(this.log);
}
});
/*
Interceptor.attach(Module.findExportByName("libmsc26.so", "aes26Encrypt"), {
onEnter: function (args) {
// Logging input parameters
console.log("aes26Encrypt called with parameters:");
// Log 'mac' parameter (size: 3 bytes)
let macHex = "mac: ";
for (let i = 0; i < 4; ++i) {
const byte = Memory.readU8(args[0].add(i));
macHex += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
console.log(macHex);
// Log 'uuid' parameter (size: 3 bytes, adjusted from provided size)
let uuidHex = "uuid: ";
for (let i = 0; i < 3; ++i) {
const byte = Memory.readU8(args[1].add(i));
uuidHex += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
console.log(uuidHex);
// Log 'uid' parameter (size: 3 bytes)
let uidHex = "uid: ";
for (let i = 0; i < 3; ++i) {
const byte = Memory.readU8(args[2].add(i));
uidHex += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
console.log(uidHex);
// Log 'groupId' parameter
console.log("groupId: " + args[3].toInt32());
// Log 'cmd' parameter
console.log("cmd: " + args[4].toInt32());
// Log 'sn' parameter
console.log("sn: " + args[5].toInt32());
// Log 'data' parameter (size: 3 bytes)
let dataHex = "data: ";
for (let i = 0; i < 3; ++i) {
const byte = Memory.readU8(args[6].add(i));
dataHex += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
console.log(dataHex);
// Preserve 'outputData' pointer for use in onLeave
this.outputData = args[7];
},
onLeave: function (retval) {
// Log 'outputData' after function execution (size: 26 bytes)
let outputDataHex = "outputData: ";
for (let i = 0; i < 26; ++i) {
const byte = Memory.readU8(this.outputData.add(i));
outputDataHex += "0x" + byte.toString(16).padStart(2, '0') + ", ";
}
console.log(outputDataHex);
}
});
//*/
}
// Start the monitoring process
waitForLibraryLoad();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment