Another POC, (ab)using the mzrm system. Since there are unused message IDs on the Xtensa side, it is possible to replace the NULL entries in the message handler table with pointers to our custom functions. I chose ID #1.
Addresses are for sx280 102b.
// mzrm_create's typical return pointer is 0xBFF004D8
int mzrmtrial1(int a1, int a2, int a3) {
extern int* _mzrm_create(int handle, int type, int id, int length);
extern int _mzrm_send(int handle, int* msg);
int * p = _mzrm_create(*(int*)0x17f8c, a1, a2, a3); // the firmware uses 0x17f8c as the pointer to the handle
if (a3>3) {
*(p+3) = 0xcafecafe;
}
return _mzrm_send(*(int*)0x17f8c, p);
//return (int)p;
}
void mypoke1() {
char myprg[] = {
0x36, 0x41, 0x00, // entry a1, 32
0xA2, 0x22, 0x00, // l32i a10, a2, 0
0xA0, 0x2A, 0x20, // or a2, a10, a10
0x1D, 0xF0, // retw.n
0x00
};
memcpy((void*)0xbff25800, myprg, 12);
*(int*)0x80a001d4 = 0xbff25800; // msg1 (dodgy, xtensa has a cache too)
}
NHSTUB(mzrm_create, 0xFC254691)
NHSTUB(mzrm_send, 0xFC25476D)
After compilation, I looked up the address of mzrmtrial1() and mypoke1() and used them in chdkptp, with call_func_ptr.
mypoke1() copies a short function to the TCM-like code memory of the Zico core. I'm using a location in its unused part (the 0xbff20000 blob ends earlier than 0xbff25800). the word at 0x80a001d4 is the second entry in the message handler table, it is NULL originally.
My Xtensa message handler returns the first word of the message (or something random if the message is zero sized). Surprisingly(?), the return value is actually passed back to the ARM side and becomes the return value of mzrm_send.
This is one possible way to execute code on the Xtensa. The other way is to modify the blobs before the Zico core is started. zicokick_start (the routine that copies the Xtensa blobs) does attempt to call an optional function pointer for logging purposes - that would very likely be usable as a point to hijack the routine and modify the binaries.